我是 haskell 和一般函数式编程的新手,我对 monad 有疑问。假设我有一个文件名列表:
-- do block --
let filenames = ["file1","file2"]
我想使用列表理解生成这些文件内容的列表:
let content = [str <- readFile f | f <- filenames]
Ofc,这种用法是无效的。 据我了解,当将结果与下一条指令“链接”时,可以在 do block 中使用这种“赋值”。
是否有其他方法可以使用左箭头(或 >>=)运算符。我想象这样的事情:
let content = [leftArrAlter $ readFile f | f <- filenames]
最佳答案
让我们从更简单的列表开始
let content = [readFile f | f <- filenames]
content
类型为 [IO String]
;这是 IO
的列表 Action ,每个 Action 都可以产生一个 String
执行时。
您想要的是 IO [String]
类型的东西: 单个 IO
执行时会为您提供 String
列表的操作值(value)观。
这就是 sequence
的位置函数进来了。在这种情况下,我们只需要考虑类型为 [IO String] -> IO [String]
的专用版本。 :
content <- sequence [readFile f | f <- filenames]
我们也可以使用traverse
,特别是类型为 (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)
我们使用了 []
作为我们的 Traversable
, 和 IO
作为我们的 Monad
/Applicative
.
关于Haskell 左箭头运算符替代,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67534392/