Tor*_*nny 3 monads tree haskell function
我想编写一个函数,可以在Haskell中以广度优先的方式递归列出目录.如您所见,我需要一个可以将(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 = ??????????
Run Code Online (Sandbox Code Playgroud)
一般情况下,您不能以纯粹的方式执行此操作,但如果您可以枚举所有参数值,则可以预先执行所有IO并返回纯函数.就像是
cacheForArgs :: [a] -> (a -> IO b) -> IO (a -> b)
cacheForArgs as f = do
bs <- mapM f as
let abs = zip as bs
return $ \ a -> fromMaybe (error "argument not cached") $ lookup a abs
cacheBounded :: (Enum a, Bounded a) => (a -> IO b) -> IO (a -> b)
cacheBounded = cacheForArgs [minBound .. maxBound]
Run Code Online (Sandbox Code Playgroud)
但是这个功能对你的用例并没有多大帮助.
这是不可能做到的.原因是该函数可以使用其类型的参数a来确定IO执行的操作.考虑
action :: Bool -> IO String
action True = putStrLn "Enter something:" >> getLine
action False = exitFailure
Run Code Online (Sandbox Code Playgroud)
现在,如果你以某种方式转换它IO (Bool -> String)并评估这个动作,会发生什么?没有解决方案.我们无法决定是否应该读取字符串或退出,因为我们还不知道Bool参数(如果没有在参数上调用结果函数,我们可能永远不会知道它).
约翰的回答是个坏主意.它只是让IO动作逃避纯粹的计算,这将使你的生活变得悲惨,你将失去Haskell的参考透明度!例如运行:
main = unsafe action >> return ()
Run Code Online (Sandbox Code Playgroud)
即使调用了IO操作,也不会执行任何操作.而且,如果我们稍微修改一下:
main = do
f <- unsafe action
putStrLn "The action has been called, calling its pure output function."
putStrLn $ "The result is: " ++ f True
Run Code Online (Sandbox Code Playgroud)
你会看到,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)效果中必须修复.