Search code examples
functionhaskellhigher-order-functionsdo-notation

How to draw from function with arguments in Haskell?


I know that inside a do block I can draw from something monadic, "extracting" its contents. For instance, if I have a function with signature:

myFunction :: MyReader (Set Int)

I can do this inside a do block:

mySet <- myFunction

This will give me the Set Int I want. However, if I change my function so that it takes an argument:

myFunction :: Int -> MyReader (Set Int)

I can no longer do what I want:

myFunction' <- myFunction

This fails to compile with error Couldn't match expected type and Probable cause: ‘myFunction'’ is applied to too few arguments. Trying something like this is not even syntactically correct:

myFunction' x <- myFunction x

I do want myFunction' to be of type Int -> Set Int. I can't figure out or find anywhere how to do what I want. Can anyone help, please?


Solution

  • This could be what you are looking for: (untested)

    data MyEnv = MyEnv { myFn :: Int -> Set Int }
    type MyReader a = Reader MyEnv a
    
    myFunction :: Int -> MyReader (Set Int)
    
    something = do
         ...
         myFunction' <- reader (\env x -> runReader (myFunction x) env)
         -- here myFunction' :: Int -> Set Int
    

    It is kind of ugly, though, since it breaks the abstraction and rebuilds it. Maybe there's a cleaner way, but since it's impossible to do the same in an arbitrary monad, we really need to break the abstraction somehow.

    You could at least keep the gory details in a helper function:

    flipReader :: (a -> Reader b c) -> Reader b (a -> c)
    flipReader r = reader (\y x -> runReader (r x) y)
    

    and then:

    something = do
        ...
        myFunction' <- flipReader myFunction