I want to write a function that can list a directory recursively in breadth-first in Haskell.
As you can see I need a function that can convert a (a -> IO b) to a IO (a->b). Simple as it seems, I can’t make it. And I want to know how to do or whether it is possible.
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 = ??????????
This cannot be done. The reason is that the function can use its argument of type
ato determine whatIOaction is executed. ConsiderNow if you’d convert it somehow to
IO (Bool -> String)and evaluate this action, what should happen? There is no solution. We cannot decide if we should read a string or exit, because we don’t know theBoolargument yet (and we may never know it, if the resulting function isn’t called on an argument).John’s answer is a bad idea. It simply lets the IO action escape into pure computations, which will make your life miserable and you’ll lose Haskell’s referential transparency! For example running:
will do nothing even though the IO action was called. Moreover, if we modify it a bit:
you’ll see that the
actionthat asks for an input is executed in a pure computation, inside callingf. You’ll have no guarantee when (if at all) the action is executed!Edit: As others pointed out, it isn’t specific just to
IO. For example, if the monad wereMaybe, you couldn’t implement(a -> Maybe b) -> Maybe (a -> b). Or forEither, you couldn’t implement(a -> Either c b) -> Either c (a -> b). The key is always that fora -> m bwe can choose different effects depending ona, while inm (a -> b)the effect must be fixed.