I am trying to write a Haskell "number-guessing" game program, using Monads, but I am stucked:
I tried the simple state monad:
data SM a = SMN (S -> (a, S))
instance Monad SM where
SMN c1 >>= fc2 = SMN (\s0 -> let (r, s1) = c1 s0 in
let SMN c2 = fc2 r in
c2 s1)
And I need to perform the IO tasks on the "IO-side" of the tuple (a, S), that is, I tried doing something like:
SMN c1 >>= fc2 = SMN (\s0 -> let (r, s1) = c1 s0 in
let SMN c2 = fc2 r in
let (r1, s2) = c2 s1 in
let r2 = r1 >>= (\_ -> r) in
(r2, s2))
In short, the bind operator I would like to define is the same as the original state monad, except that we bind r1 and the constant function that takes an argument to r (so that the two actions are chained together). But the ghc tells me that a is a rigid type variable... What does that mean? I cannot use another bind operator inside one bind operator?
If so, then is there a way to implement such a bind operator? How?
As I am new to Haskell(I think I might have had a notational error concerning the function
\_ -> r
), any opinion and reference are welcomed, thanks in advance.
P.S. I used different notations for the data type SM and the type constructor SMN, so as to differentiate them.
The type of (>>=)
is:
Monad m => m a -> (a -> m b) -> m b
Since you are writing an instance for SM
, the type of bind in your instance is therefore
SM a -> (a -> SM b) -> SM b
Notice that both a
and b
are completely unrestricted type variables. That means whatever implementation you give must work no matter what types I choose to put in there. In particular, I could choose, say, Int
for both a
and b
:
SM Int -> (Int -> SM Int) -> SM Int
And now it is clear why your implementation is no good: it will attempt to treat an Int
as if it were a monadic action and call (>>=)
on it.
If you want to be able to do monadic actions inside your bind, you will have to talk about the monad in your type somehow; for example, one standard way is to define
data SMT m a = SMT (S -> m (a, S))
and give an instance like:
instance Monad m => Monad (SMT m) where -- ...
The normal SM
can then be recovered, if you like, by using the Identity
monad as the nested monad.