IO字符串列表

时间:2014-03-06 02:29:08

标签: haskell io

我是Haskell和FP的新手,所以这个问题可能看起来很傻。

我的主要功能

中有一行代码
let y = map readFile directoryContents

其中directoryContents的类型为[FilePath]。这反过来(我认为)使y类型[IO String],所以一个字符串列表 - 每个字符串包含directoryContents中每个文件的内容。

我有一个函数写在另一个模块中,可用于[String]String,但我现在还不清楚如何调用/使用它们,因为y的类型为[IO String]。有什么指针吗?


修改

有人建议我使用mapM代替map,所以:

let y = mapM readFile directoryContentsy现在是IO [String],我该怎么做?

1 个答案:

答案 0 :(得分:22)

你是对的,类型是y :: [IO String]

嗯,这里主要有两个部分:

如何将[IO String]转换为IO [String]

[IO String]IO个动作的列表,我们需要的是一个带有字符串列表的IO动作(即IO [String])。幸运的是,函数序列提供了我们所需要的:

sequence :: Monad m => [m a] -> m [a]
y' = sequence y :: IO [String]

现在mapM函数可以简化此操作,我们可以将y'重写为:

y' = mapM readFile directoryContents

mapM为我们做了序列。

如何到达[String]

我们的类型现在是IO [String],所以现在的问题是“我们如何从IO中获取[String]?”这就是函数>>=(bind)的作用:

(>>=) :: Monad m => m a -> (a -> m b) -> m b
  -- Specialized to IO, that type is:
(>>=) :: IO a -> (a -> IO b) -> IO b

我们还有一个函数return :: Monad m => a -> m a,它可以将值“加入”IO

所以使用这两个函数,如果我们有一些函数f :: [String] -> SomeType,我们可以写:

ourResult = y' >>= (\theStringList -> return (f theStringList))  :: IO SomeType

函数可以与>>=函数一起“链接”。这有时可能有点难以理解,因此Haskell提供了do符号,使视觉上更简单:

ourResult = do
  theStringList <- y'
  return $ f theStringList

编译器在内部将其转换为y' >>= (\theStringList -> f theStringList),这与我们之前的y' >>= f相同。

全部放在一起

我们可能实际上并不希望y'浮动,所以我们可以消除它并到达:

ourResult = do
  theStringList <- mapM readFile directoryContents
  return $ f theStringList

更简化

事实证明,这实际上并不需要>>=的全部力量。事实上,我们所需要的只是fmap!这是因为函数fIO内部只有一个参数,我们没有使用任何其他先前的IO结果:我们正在制作一个结果,然后立即使用它。

使用法律

fmap f xs  ==  xs >>= return . f

我们可以重写>>=代码来使用这样的fmap:

ourResult = fmap f (mapM readFile directoryContents)

如果我们想要更加简洁,那么fmap<$>的中缀同义词:

ourResult = f <$> mapM readFile directoryContents