Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I think I found a "non-existent monad"

I found a weird feature of Haskell which made me believe I am thinking in the wrong way. I think in Haskell, there should be some "non-existent" monad. This is because of the following.

Prelude> return 1
1
Prelude> return 1 >>= \x -> if even x then return True else return False
False

>>= is of type m a -> (a -> m b) -> m b where m can be any monad. My theory is this: since return 1 evaluates to a mere 1, return 1 can be thought of as a 1 lifted to a value wrapped inside of a "non-existent" monad. Haskell captured this fact and evaluated the entire expression

return 1 >>= \x -> if even x then return True else return False

to False since it has to yield a "non-existent False" which is a mere False.

However, I have never heard about such "non-existent" monads before.

I am sure I am theorizing it in the wrong way, because if "non-existent 1" is just 1, the following expression must be type consistent, but it is not. It is a modified version of the above one.

1 >>= \x -> if even x then return True else return False

<interactive>:57:1: error:
    • Could not deduce (Integral a0)
      from the context: (Monad m, Integral a, Num (m a))
        bound by the inferred type for ‘it’:
                   forall (m :: * -> *) a. (Monad m, Integral a, Num (m a)) => m Bool
        at <interactive>:57:1-56
      The type variable ‘a0’ is ambiguous
    • In the ambiguity check for the inferred type for ‘it’
      To defer the ambiguity check to use sites, enable AllowAmbiguousTypes
      When checking the inferred type
        it :: forall (m :: * -> *) a.
              (Monad m, Integral a, Num (m a)) =>
              m Bool

So, there must be a contradiction in my theory. What am I missing?

like image 659
Namudon'tdie Avatar asked Dec 07 '22 11:12

Namudon'tdie


1 Answers

return 1 isn't just 1. What you think is the "non-existent monad" is really IO. When you use return 1, GHCi is assuming that you mean IO, and then helpfully executing the IO expression and displaying the result. You get a type error with 1 >>= ... because 1 isn't a monad.

As @bradrn mentions in the comments, in general GHCi automatically runs any IO a value you give it, and then prints out the value it returns; if you give GHCi a non-IO type value, it will just print that value (if it can).

As an aside, there is a monad called Identity which essentially does work as a "non-existent monad" as you put it, in that return x is isomorphic to x no matter what you put in it. It doesn't get used automatically, though; you'd need to manually wrap and unwrap it to use it.

like image 139
Joseph Sible-Reinstate Monica Avatar answered Jan 14 '23 19:01

Joseph Sible-Reinstate Monica