foldl和IO值

时间:2013-01-15 21:31:48

标签: haskell io fold

我有这样的代码:

foldl (\a x -> a ++ (f x)) [] list

似乎一切正常,但是(f x) :: IO [String](++)会出错([String]!= IO [String])。

如何定义空IO [String]列表?我不能干净(f x)。

3 个答案:

答案 0 :(得分:12)

你想要的组合器可能是

Prelude Control.Monad> :t foldM
foldM :: Monad m => (a -> b -> m a) -> a -> [b] -> m a

和那个

foldM (\a x -> fmap (a++) (f x)) [] list

按顺序运行操作f x并累积他们生成的[String]

答案 1 :(得分:3)

在:

foldl (\a x -> a ++ (f x)) [] list

你正在尝试a ++ f xf x :: IO [String],所以它不起作用。让我们看看我们是否可以解决正在发生的事情。

您的意思是x来自list,因此您将依次将f应用于列表中的每个元素,并且每个元素都会给您{ {1}}并且您希望在进行中将它们连接在一起。

我们将使用[String],它将一个函数映射到一个列表,然后将monad操作一起排序为一个,将输出组合成一个列表。

mapM :: Monad m => (a -> m b) -> [a] -> m [b]

这里我使用concatMapM :: (a -> IO [String]) -> [a] -> IO [String] concatMapM f list = fmap concat (mapM f list) 将纯函数fmap应用于IO操作的结果。

您可以使用

进行测试
concat

fileLines :: FilePath -> IO [String]
fileLines filename = fmap lines (readFile filename)

这种方式比尝试折叠更好,因为*Main> concatMapM fileLines ["test1.txt","test2.txt"] ["This is test1.txt","It has two lines.","This is test2.txt","It has two lines too."] concat效率更高。要自己检查一下,请将它们与速度进行比较:

foldl (++)

问题是*Main> writeFile "test3.txt" $ foldl (++) [] (map show [1..10000]) *Main> writeFile "test3.txt" $ foldr (++) [] (map show [1..10000]) 执行foldl因此会在列表(((a++b)++c)++d)++e中运行四次 - 它会在添加a时首先运行它,然后它会贯穿{ {1}}和b添加a,然后在添加b时运行cab,然后当它添加c时,会遍历所有这四个。这是一个很大的浪费。

d执行e因此会在每个列表中运行一次 - foldr然后a ++ (b ++ (c ++ (d ++ e)))然后d然后cba,对于此列表操作来说要好得多。

答案 2 :(得分:1)

假设您有以下内容:

list :: [a]
f :: a -> IO b

我假设您希望获得类型为IO [b]的最终值。如果您将f映射到list,则会得到类型[IO b]的列表。您可以使用sequence :: Monad m => [m a] -> m [a]将IO从内部移动到外部,如下所示:

sequence (map f list) :: IO [b]

以这种方式思考:在排序之前,您有一个用于创建类型b的值的指令列表。现在您只需要一条指令来制作b的列表。