I have the following code:
import Control.Monad
coin :: MonadPlus m => m Int
coin = return 0 `mplus` return 1
If I evaluate coin :: Maybe Int
on the interpreter, it prits Just 0
. That's normal because of the implementation of Maybe as instance of MonadPlus.
If I evaluate coin :: [Int]
on the interpreter, it prints [0, 1]
, because the implementation of mplus
on list is an append
.
But if I evaluate coin
, without any type decorators, it prints 0
. Why? What type does the interpreter 'converts' coin
to evaluate it?
This code is extracted from: http://homes.sice.indiana.edu/ccshan/rational/S0956796811000189a.pdf
Bind takes a non-composable function f and returns a new function g that accepts the monadic type as input and returns the monadic type. g is composable. The unit function takes an argument of the type that f expected, and wraps it in the monadic type.
What is a Monad? A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.
A monadic function is a function with a single argument, written to its right. It is one of three possible function valences; the other two are dyadic and niladic. The term prefix function is used outside of APL to describe APL's monadic function syntax.
Monads are simply a way to wrapping things and provide methods to do operations on the wrapped stuff without unwrapping it. For example, you can create a type to wrap another one, in Haskell: data Wrapped a = Wrap a. To wrap stuff we define return :: a -> Wrapped a return x = Wrap x.
Yeah, this is a not super-well documented corner of ghci. When you enter an expression into ghci, it uses the expression's type to decide what to do:
IO ()
: Run the action, do nothing further.Show a => IO a
: Run the action and print
the result.IO a
: Run the action, do nothing further.print
.How does it decide which of these types a thing has? Easy: it tries to unify the type of your expression which each of the above signatures in turn and solve all resulting constraints. (For the cognoscenti: this is in addition to the extended defaulting rules! This explains why it appears to be defaulting the m
, even though neither the standard defaulting rules nor the extended defaulting rules say what default to use.)
So, since your expression does not unify with IO ()
but does unify with Show a => IO a
, ghci finds m ~ IO
(and a ~ Int
) during unification, discovers that there is a MonadPlus IO
(and a Show Int
) instance to resolve the constraints, runs your action, and prints the result.
GHCi (but not GHC in general) will, in the absence of a signature specifying otherwise, specialise polymorphic type constructors to IO
whenever possible. IO
actions at the prompt, in turn, are executed and have their results monadically bound to the it
variable, which is then printed (i.e. do { it <- action; print it }
) as long as there is a Show
instance for the result type (cf. Daniel Wagner's answer). For more details, have a look at the I/O actions at the prompt and The it variable sections of the User's Guide.
In your specific case, it happens that there is a MonadPlus
instance for IO
. You get return 0
from it because mplus
for IO
only executes the second action if the first one throws an exception. One demonstration:
GHCi> readLn `mplus` readLn :: IO Integer
0
0
GHCi> readLn `mplus` readLn :: IO Integer
foo
1
1
GHCi> readLn `mplus` readLn :: IO Integer
foo
bar
*** Exception: user error (Prelude.readIO: no parse)
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