2012-09-28 58 views
1

我有一個列表裏面有一個字符串,我需要通過Char解構Char,並把它作爲Integer放入列表中,但是我受到類型的阻礙有一個字符串列表,但需要一個整數列表

我有什麼是我讀入單子一個txt文件:

getTxt = do 
    y <- readFile "foo.txt" 
    return y 

foo只包含此:

"1234567890\n" 

然後我想我是密切與序列但讓我THI s清單:

["1","2","3","4","5","6","7","8","9","0"] :: [[Char]] 

但我需要[Integer]ord將採取Char -> Int但我怎麼讀[Char] -> [Int]?在所有這些試驗和唯一的錯誤之後,我不需要最後過濾掉最後一個新行?

有什麼建議嗎?

+3

這個問題可能會有所幫助:http://stackoverflow.com/questions/2468410/convert-string-to-integer-float-in-haskell – jrajav

回答

1

如果使用ord,該類型匹配,但它不是你想要的,因爲ord給你 ASCII值,而不是數值:ord 553,不5。您可以減去 48以獲取數字,然後將數字向上滾動到一個數字中,但它會更容易使用庫函數。最簡單的選擇是read

getInt :: IO Integer 
getInt = do 
    y <- readFile "foo.txt" 
    return (read (takeWhile (/='\n') y)) 

正如linked answer, 這裏最好的解決方案是使用reads

reads發現可能匹配的列表, 作爲對(match,remainingstring), 這是因爲它會自動離開換行符剩餘的字符串爲你工作得很好,

*Main> reads "31324542\n" :: [(Integer,String)]
[(31324542,"\n")]

讓我們使用即:

findInt :: String -> Maybe Integer 
findInt xs = case reads xs of    -- have a look at reads xs 
    ((anint,rest):anyothers) -> Just anint -- if there's an int at the front of the list, just return it 
    _ -> Nothing       -- otherwise return nothing 

Maybe是一種方便的數據類型,可以讓您在沒有崩潰程序或執行異常處理的情況下發生故障。 Just 5意味着你得到了輸出,它是5Nothing意味着有問題,沒有輸出。

addTen :: FilePath -> IO() 
addTen filename = do 
    y <- readFile filename 
    case findInt y of 
     Just i -> putStrLn ("Added 10, got "++show (i+10)) 
     Nothing -> putStrLn ("Didn't find any integer at the beginning of " ++ filename) 

它給你:

*Main> addTen "foo.txt"
Added 10, got 1234567890


如果你只是想字符代表的整數,你可以在你的文件的頂部放import Data.Char

ordzero = ord '0' -- handy constant, 48, to unshift the ascii code to a digit. 

getInts :: FilePath -> IO [Int]   -- ord gives the smaller Int, not Integer 
getInts filename = do 
    y <- readFile filename 
    return [ord achar - ordzero | achar <- takeWhile isDigit y] 

這需要字符串y的人物,只要他們的數字,然後 發現自己ord,減去ord '0'(這是48)把'4'4

0

閱讀文檔mapfilter。這非常重要。 在你的情況

integersFromFile :: String -> IO [Int] 
integersFromFile filename = map digitToInt <$> readFile filename 
+0

你可能是指'integersFromFile名=地圖ORD <$> READFILE filename'因爲代碼不會檢查。 –

+0

是的。你說得對。而且,我沒有仔細檢查,OP是否需要digitToInt。 – KAction

0

我不明白你在說什麼,但我的東西,我認爲illusionoflife是在暗示版本列表理解...

do cs <- readFile "foo.txt" 
    return [ord c | c <- cs, c /= '\n'] 

這是有點作弊 - 它假設文件只包含數字和行結束符,並且只是在任何發生的地方剝掉任何行尾字符。

說明 - 這是一個list comprehensionc <- cs基本上依次分配c每個字符。 c /= '\n'過濾出行結束的案例(無論它發生在哪裏 - 它不一定非要結尾)。 ord c給出了包含在最終列表中的值。

這可以用filtermap來表示,但是一旦你習慣了它,列表理解就更方便了。

改進後的版本可能會使用isDigit(來自Data.Char)來檢查字符。 Maybe還有一種跟蹤列表中是否有無效字符的方法,因此您可以稍後檢查並報告這些標記,也可以將其過濾掉。

+0

糟糕 - 是的,抱歉,我沒有想到,我一直沒有使用Haskell。現在應該修復。 – Steve314

+0

感謝您的編輯 – AndrewC

0

所以,你想有一個函數這種類型:

charsToInts :: [Char] -> [Int] 

我們可以通過將問題分解成更小的問題來解決這個問題。首先,我們需要一個轉換功能的單CharString

charToString :: Char -> String 
charToString c = [c] 

...那麼我們需要轉換一個StringInt功能:

stringToInt :: String -> Int 
stringToInt = read 

...那麼我們撰寫這兩個函數來獲取轉換Char個功能Int S:

charToInt :: Char -> Int 
charToInt = stringToInt . charToString 

無W,我們可以解除該功能通過使用map處理的Char秒的整個列表:

charsToInts :: [Char] -> [Int] 
charsToInts = map charToInt 

...我們就大功告成了!

我爲了演示目的採取了非常詳細的路徑。在我自己的代碼,我通常會內聯像這樣所有這些定義:

charsToInts :: [Char] -> [Int] 
charsToInts = map (read . singleton) 
    where singleton x = [x] 

要在代碼中使用stringsToInts,你會這樣寫:

getTxt :: IO [Int] 
getTxt = fmap charsToInts $ readFile "foo.txt" 

fmap適用charsToIntsreadFile結果,和上面的代碼等同於:

getTxt = do 
    chars <- readFile "foo.txt" 
    return $ charsToInts chars 

[外評論:

你甚至可以進一步降低它,與列表理解:

getTxt :: IO [Int] 
getTxt = do 
    chars <- readFile "foo.txt" 
    return [read [d] | d <- chars] 

注意到,雖然類型標註爲頂級功能一般都是一個好主意,在這種情況下,它是強制性的(除非你把一個註解進入功能體)。這是因爲「閱讀」,否則不知道你想要什麼類型。 ]

相關問題