2010-12-09 104 views
4

我的目標是編寫Haskell函數,它從輸入中讀取N行並將它們加入到一個字符串中。下面是第一次嘗試:Haskell將[IO字符串]加入IO字符串的方式

readNLines :: Int -> IO String 
readNLines n = do 
    let rows = replicate n getLine 
    let rowsAsString = foldl ++ [] rows 
    return rowsAsString 

上。這裏foldl Haskell的投訴:

不能匹配預期類型[a]' against inferred type(A1 - >乙 - > A1) - > A1 - >並[b] - > A1'

按我的理解是行的[IO String]類型,是否有可能一些如何在一個IO String加入該名單?

回答

6

再說什麼ephemient指出,我認爲你有一個語法問題:您正在使用的++操作的方式使它看起來像你試圖調用++操作符與操作數foldl[]。把++運營商在括號中,使你的意圖明顯:

foldl (++) [] rows 
+0

啊,是的,這是typecheck錯誤的直接原因......我忽略了,因爲即使OP修復後,他們仍然有另一個問題。 – ephemient 2010-12-09 19:34:16

+0

還應該注意'foldl(++)[]`與`concat`相同。 – HaskellElephant 2010-12-09 23:29:35

5

你正在尋找的是一個功能是sequence,然而,應該指出的是,

sequence (replicate n f) 

相同

replicateM n f 

foldl (++) []相當於concat。所以,你的功能是:

readNLines n = liftM concat (replicateM n getLine) 

另外,如果要保留換行:

readNLines n = liftM unlines (replicateM n getLine) 
0

replicate返回IO String操作的列表。爲了執行這些操作,它們需要在IO monad中運行。所以你不想加入IO操作數組,而是依次運行它們並返回結果。

這裏就是我會做

readNLines :: Int -> IO String 
readNLines n = do 
    lines <- replicateM n getLine 
    return $ concat lines 

或者,在應用性風格:

import Control.Applicative 

readNLines :: Int -> IO String 
readNLines n = concat <$> replicateM n getLine 

這兩種使用一元重複(replicateM),其評估序列一元值的列表,而不是簡單地返回一個動作列表

1

我可以拿出的最短答案是:

import Control.Applicative 
import Control.Monad 

readNLines :: Int -> IO String 
readNLines n = concat <$> replicateM n getLine