我想编写一个函数,可以在 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/