如何在Haskell中从 - > IO b创建IO(a-> b)函数

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)

aug*_*tss 6

一般情况下,您不能以纯粹的方式执行此操作,但如果您可以枚举所有参数值,则可以预先执行所有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)

但是这个功能对你的用例并没有多大帮助.


Pet*_*lák 5

这是不可能做到的.原因是该函数可以使用其类型的参数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)效果中必须修复.