function - 如何在 Haskell 中从 a -> IO b 生成 IO (a->b) 函数

标签 function haskell tree monads

我想编写一个函数,可以在 Haskell 中以广度优先的方式递归列出目录。 正如你所看到的,我需要一个可以将 a (a -> IO b) 转换为 IO (a->b) 的函数。看似简单,我却做不到。我想知道该怎么做或者是否可能。

dirElem :: FilePath -> IO [FilePath]
dirElem dirPath = do
  getDirectoryContents'' <- theConvert getDirectoryContents'
  return $ takeWhile (not.null) $ iterate (concatMap getDirectoryContents'') [dirPath] where
    getDirectoryContents' dirPath = do
      isDir <- do doesDirectoryExist dirPath
      if isDir then dirContent else return [] where
        dirContent = do
          contents <- getDirectoryContents dirPath
          return.(map (dirElem</>)).tail.tail contents
    theConvert :: (a -> IO b) -> IO (a -> b)
    theConvert = ??????????

最佳答案

这是无法完成的。原因是该函数可以使用其a类型的参数来确定执行什么IO操作。考虑一下

action :: Bool -> IO String
action True  = putStrLn "Enter something:" >> getLine
action False = exitFailure

现在,如果您以某种方式将其转换为 IO (Bool -> String) 并评估此操作,会发生什么?没有解决办法。我们无法决定是否应该读取字符串或退出,因为我们还不知道 Bool 参数(如果没有在参数上调用结果函数,我们可能永远不会知道它)。

约翰的回答是一个主意。它只是让 IO 操作转入纯粹的计算,这会让你的生活变得悲惨,并且你将失去 Haskell 的引用透明度!例如运行:

main = unsafe action >> return ()

即使调用了 IO 操作,也不会执行任何操作。此外,如果我们稍微修改一下:

main = do
   f <- unsafe action
   putStrLn "The action has been called, calling its pure output function."
   putStrLn $ "The result is: " ++ f True

您将看到请求输入的action是在调用f内部以纯计算执行的。您无法保证该操作何时(如果有的话)执行!

编辑:正如其他人指出的那样,它不仅仅特定于IO。例如,如果 monad 是 Maybe,则无法实现 (a -> Maybe b) -> Maybe (a -> b)。或者对于 Either,您无法实现 (a -> Either c b) -> Either c (a -> b)。关键始终是,对于 a -> m b,我们可以根据 a 选择不同的效果,而在 m (a -> b) 中,效果必须是固定的。

关于function - 如何在 Haskell 中从 a -> IO b 生成 IO (a->b) 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14432883/

相关文章:

java - 自下而上填充一棵树

javascript - 节点有时有多个父节点的数据集,如何以树状方式显示它? (d3.js 或类似的东西)

c++ - 为什么它试图发送一个字符数组而不是一个字符串?

haskell - 了解 Haskell 访问器函数

unit-testing - 模拟 IO 操作 : getArgs and putStrLn

algorithm - 如何优化这个 Haskell 代码在亚线性时间内总结素数?

c++ - 在不提供参数类型的情况下绑定(bind)函数

c - 为什么链接器不抛出多个函数声明错误?

c - 函数中的字符串在 C 中不被修改

c++ - 如何在磁盘上存储一棵树并使添加/删除/交换操作变得容易