Search code examples
haskellfunctional-programmingmonadsio-monadlifting

Transformation of (a -> IO b) to IO (a -> b)


I have several data types in an IO context like:

a :: IO String
b :: IO FilePath
c :: String -> IO String

I want to put them all together in one data object like:

data Configdata = Configdata String FilePath (String -> String)

So I don't have to get each value for its own out of the IO context, but just out of IO Configdata.

The critical point where I don't have a solution is how I can transform String -> IO String to IO (String -> String). Hoogle doesn't give me any functions which are capable of doing this.

I am not sure if it's maybe even not possible, since the input of the function is possibly infinite.

Does someone have a solution or an explanation why it's not possible? I know that using a list instead of a function is an option, but I would prefer using a function if possible.


Solution

  • Indeed this is not possible. Consider the function:

    import Acme.Missiles
    
    boo :: String -> IO String
    boo "cute" = return "Who's a nice kitty?"
    boo "evil" = launchMissiles >> return "HTML tags lea͠ki̧n͘g fr̶ǫm ̡yo​͟ur eye͢s̸ ̛l̕ik͏e liq​uid pain"
    

    Now, if it were possible to transform this to IO (String -> String), it would have to execute all possible IO actions for any input before returning the pure String -> String function. IOW, even if you only planned to use the function for kitten-watching purposes, it would entail nuclear holocaust.

    Nevertheless, it may well be possible to do this for your specific application. In particular, if you know the function will only ever be called for a predetermined set of strings, you can pre-query them from IO and store the results in a map, which can then be indexed purely.

    import qualified Data.Map as Map
    
    puh :: IO (String -> String)
    puh = fmap ((Map.!) . Map.fromList) . forM ["cute"] $ \q -> do
           res <- boo q
           return (q, res)
    

    Of course, this may not be feasible performance-wise.