2

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?

arussell84
  • 2,443
  • 17
  • 18
  • What do you think `myFunction' <- myFunction` does? Basically this only makes sense in a MyReader monad context, but then `myFunction'` is not a function. Maybe you meant `mySet <- myFunction` and the analogous `mySet <- myFunctionWithAParameter 1`? – Niklas B. Nov 01 '14 at 10:07
  • Sorry, @NiklasB.. That was bad naming. Ultimately I **do** want it to be a function rather than a set. – arussell84 Nov 01 '14 at 10:11
  • @arussell84- You can pull a function out of a monad, but the type would have to be a wrapped function, like `MyReader (a->b)`, not `MyReader (Set Int)`. – jamshidh Nov 01 '14 at 10:14
  • I realize this, @jamshidh. Do you know of a way to easily transform `Int -> MyReader (Set Int)` to `MyReader (Int -> Set Int)`? I'm still looking for a solution! – arussell84 Nov 01 '14 at 10:16
  • @arussell84- so you want to turn a monadic function into a pure function, but only be able to use it in the active do block? Does that sound correct? – jamshidh Nov 01 '14 at 10:25
  • Yes, @jamshidh, that sounds correct. – arussell84 Nov 01 '14 at 10:37
  • Honestly, I don't know if this can be done, and I have wondered myself before. It feels unlikely to me, because if it could be done, it would have to be possible for all monads, but how would you change something like `a->Maybe b` to `Maybe (a->b)`.... I'd love to hear other thoughts on this. – jamshidh Nov 01 '14 at 10:45
  • 2
    There can exist no function `(Monad m) => (a -> m b) -> m (a -> b)`. That would essentially mean transforming a monadic function into a pure function. – Niklas B. Nov 01 '14 at 11:04
  • Instead maybe you should describe what you want to achieve and we can give you a clean solution – Niklas B. Nov 01 '14 at 11:05
  • While impossible in general, in the specific case of the reader monad this seems possible if you break the abstraction (e.g. `runReader`) and flip the arguments. Is the `MyReader` monad the standard one? Can you show us its definition? – chi Nov 01 '14 at 12:14
  • Based on everyone's answers, I am thinking it is not possible in Haskell. My question here is not about finding a workaround, so I am not going to ask for one. What I have learned from asking this question is that the `<-` operator is limited in that it simply does not work for functions. It works fine for values, so I figured I'd ask about functions, as well. – arussell84 Nov 01 '14 at 12:15
  • Sure, @chi . First, I have `data MyEnv = MyEnv { myFn :: Int -> Set Int }`, and then `type MyReader = Reader MyEnv`. What you say sounds interesting, at least. Mind showing me a code snippet as an example? – arussell84 Nov 01 '14 at 12:20
  • 1
    @NiklasB.- Do you have a reference to a proof that no such function can exist? BTW, I am nearly certain that what you say is true, but only based on some hand-wavy stuff in my head, I'd love to see something more formal. It has also proven to be a bit difficult to google.... – jamshidh Nov 01 '14 at 18:23
  • @arussell84 The `<-` operator can be used inside of a `do` block to get a reference to an `a` out of an `m a`, where `m` is a Monad. This works whether or not `a` is a function type. So, if you had a `MyReader (Int -> Set Int)`, you could use `<-` on that, because `MyReader` is the `m` and `(Int -> Set Int)` is the `a`. However, you cannot use it to pull something out of `Int -> MyReader (Set Int)`, because that is not of the form `m a`. – amalloy Nov 01 '14 at 19:03
  • 3
    If your `Monad m` also is `Distributive m` (e. g. your Reader) then you can use `distribute :: (a -> m b) -> m (a -> b)` – felix-eku Nov 01 '14 at 19:20
  • 1
    @jamshidh For a proof, assume it is possible in any monad, hence even in the continuation monad. Then, deduce a term of type `(a -> (b -> r) -> r) -> ((a -> b) -> r) -> r`. Choose `r=a` and discharge the first input. Deduce then `((a -> b) -> a) -> a`. Apply Curry-Howard and deduce Peirce's Law. Contradiction. Same trick as in http://stackoverflow.com/questions/24141972/how-to-apply-higher-order-function-to-an-effectful-function-in-haskell – chi Nov 01 '14 at 20:36

2 Answers2

1

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
chi
  • 111,837
  • 3
  • 133
  • 218
0

This will work:

result <- myFunction x

basically, myFunction has type a -> MyReader b, so myFunction x (where x :: a), has type MyReader b. As you already know, you can get the value from MyReader b by using <-, hence the expression above works.

Haskell "do" notation is kind of (very loosely speaking) like a small simple scripting language, where you can chain together "commands" (again, this is very loosely speaking), and "store" the results in "variables".

  var1 <- command1
  var2 <- command2 var1

can be read as

  run command1, store the result in var1
  then
  run command2 using var1 as a parameter, store the result in var2

Warning....

There are many monads where this analogy will break down, and be completely wrong, but for the early days, this is pretty much the only pattern beginners see for a while.

jamshidh
  • 12,002
  • 17
  • 31
  • This fails for me because `x` is not in scope. Which is why I tried adding it to both sides. – arussell84 Nov 01 '14 at 10:14
  • I think this would be easier to understand if I understood the bigger problem you are trying to solve. Can you give a sentence above on the broader problem you are trying to solve? – jamshidh Nov 01 '14 at 10:23
  • Alright, you've edited your answer, but it still does not give me what I am looking for. To be clear, I want the left-hand side to be a function of type `Int -> Set Int`. – arussell84 Nov 01 '14 at 10:24
  • In this case, no. I do not want a way **around** my problem. If the answer is that Haskell does not let me use higher order functions with the `<-` operator, that is my answer. If there is a way to easily transform `Int -> MyReader (Set Int)` to `MyReader (Int -> Set Int)`, that would be a better answer. – arussell84 Nov 01 '14 at 10:29
  • I'm not sure this is allowed by the type system. A quick [Hoogle search](https://www.haskell.org/hoogle/?hoogle=%28a+-%3E+m+b%29+-%3E+m+%28a+-%3E+b%29) for `(a -> m b) -> m (a -> b)` finds nothing. – Benjamin Hodgson Nov 01 '14 at 10:45
  • If it were on Hoogle, @BenjaminHodgson , I would not be asking on StackOverflow. – arussell84 Nov 01 '14 at 12:29
  • I'm not trying to impugn your level of research. Just saying the fact that there's no library function with that type suggests to me that it's impossible. – Benjamin Hodgson Nov 02 '14 at 00:20