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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With