Haskell左箭头运算符替代
我一般是 Haskell 和函数式编程的新手,而且我对 monad 有问题。假设我有一个文件名列表:
-- do block --
let filenames = ["file1","file2"]
我想使用列表推导生成这些文件内容的列表:
let content = [str <- readFile f | f <- filenames]
Ofc,这种用法是无效的。据我了解,这种“赋值”可以在 do 块中使用,当“链接”结果与下一条指令时。
是否有使用左箭头(或 >>=)运算符的替代方法。我想像这样:
let content = [leftArrAlter $ readFile f | f <- filenames]
回答
让我们从更简单的列表开始
let content = [readFile f | f <- filenames]
content有类型[IO String];它是一个IO动作列表,每个动作String在执行时都会产生一个。
你想要的是某种类型的东西IO [String]:一个单一的IO动作,当执行时,给你一个String值列表。
这就是sequence函数的用武之地。在这种情况下,我们只需要考虑具有 type 的专用版本[IO String] -> IO [String]:
content <- sequence [readFile f | f <- filenames]
我们也可以使用traverse,特别是带有 type 的专用版本(FilePath -> IO String) -> [FilePath] -> IO [String]:
content <- traverse readFile fileNames
供参考,两个函数的一般类型:
sequence :: (Traversable t, Monad m) => t (m a) -> m (t a)
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
我们使用[]as our Traversable,和IO我们的Monad/ Applicative。
- I'd also mention `mapM`, which is (now) equivalent to `traverse`, and its flipped version `forM`, which often makes for more readable code (`forM fileNames $ f -> do {multiple IO statements involving f}`).