IO字符串列表

use*_*427 9 io haskell

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

我的main函数中有一行代码

let y = map readFile directoryContents
Run Code Online (Sandbox Code Playgroud)

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

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


编辑:

有人向我建议我要用mapM而不是map,所以:

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

Dav*_*vid 23

你是对的,类型是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]
Run Code Online (Sandbox Code Playgroud)

现在该mapM函数可以简化这一点,我们可以重写y'为:

y' = mapM readFile directoryContents
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

我们还有一个return :: Monad m => a -> m a可以将值"放入"的功能IO.

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

ourResult = y' >>= (\theStringList -> return (f theStringList))  :: IO SomeType
Run Code Online (Sandbox Code Playgroud)

功能可以与>>=功能一起"链接" .这有时可能有点难以理解,因此Haskell提供do了使视觉上更简单的符号:

ourResult = do
  theStringList <- y'
  return $ f theStringList
Run Code Online (Sandbox Code Playgroud)

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

把它们放在一起

我们可能实际上并不想要y'漂浮,所以我们可以消除它并达到:

ourResult = do
  theStringList <- mapM readFile directoryContents
  return $ f theStringList
Run Code Online (Sandbox Code Playgroud)

更简化

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

使用法律

fmap f xs  ==  xs >>= return . f
Run Code Online (Sandbox Code Playgroud)

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

ourResult = fmap f (mapM readFile directoryContents)
Run Code Online (Sandbox Code Playgroud)

如果我们想要更简洁,有一个fmap名为的中缀同义词<$>:

ourResult = f <$> mapM readFile directoryContents
Run Code Online (Sandbox Code Playgroud)

  • 你可以使用`drop 2`.`drop 2 [".","..","a","b","c"] == ["a","b","c"]` (2认同)