Haskell:如何在另一个IO monad中处理IO monad?

时间:2011-10-20 03:17:10

标签: haskell

刚开始学习哈斯克尔 - 一周后爱上它。目前正在经历monads的痛苦,但目前还没有,但希望它会点击。

我正在尝试将类似于pythons walk()的函数放在一起但更简单。 给定一个路径,我想生成元组列表。每个子目录的元组(假设只有目录)。元组将包含目录的路径作为其第一个元素,目录包含的文件列表作为第二个元素。

我不知道我是否正确解释了它,但这是代码:

walkDir :: String -> IO [IO (FilePath, [FilePath])]
walkDir path = do
  dir <- getDirectoryContents path  
  let nd = [x | x <- dir, notElem x [".",".."]]
  return (map getcont nd)
    where
      getcont path = do
      cont <- getDirectoryContents path
      return (path,cont)

我关心的是IO里面的IO以及如何处理它?可以取消它们吗? 是否可以至少打开内部IO?这种回归是否正常?

我甚至无法打印这种回报。我是否必须创建一个show实例才能正确打印?

在某些haskell库中很可能存在类似的功能,但这是出于教育目的。我想学习。所以欢迎任何建议。

非常感谢。

2 个答案:

答案 0 :(得分:10)

mapM查看Control.Monad

然后这个

return (map getcont nd)

变为

mapM getcont nd

答案 1 :(得分:4)

让我们来看看类型。

map :: (a -> b) -> [a] -> [b]
getCont :: FilePath -> IO (FilePath, [FilePath])
nd :: [FilePath]

map getCont nd :: [IO (FilePath, FilePath)]

现在,在这一点上,结构从内向外看。我们有[IO a],但我们需要IO [a]。停止!霍格时间。推广任何ol'monad,我们都会[m a] -> m [a]。瞧,sequence有这种精确的类型签名。因此,您应使用return :: a -> m a而不是sequence :: [m a] -> m [a],而不是sequence (map getCont nd)

mapM f xs = sequence (map f xs)

然后你就会全力以赴。请注意,这与Kurt S的解决方案基本相同,因为

{{1}}