Creating monads in haskell
I want to create my own monad. This is what i wrote:
data LeafConType a = LeafCon (a,In开发者_运维知识库t,Int)
instance Monad (LeafConType ) where
return = LeafCon
lc@(LeafCon (t,i,n)) >>= f = if i>=n
then lc
else f (t,i,n)
But this dont work. Ghc says:
leafcon.hs:26:1:
Occurs check: cannot construct the infinite type: a = (a, Int, Int)
When generalising the type(s) for `return'
In the instance declaration for `Monad LeafConType'
leafcon.hs:27:1:
Occurs check: cannot construct the infinite type: a = (a, Int, Int)
When generalising the type(s) for `>>='
In the instance declaration for `Monad LeafConType'
Whats wrong with that?
I want to do calculations while i is lower than n. n should be constants by I don't know yet how to do this correct. It should be some mix of State and Maybe. If you have some advices feel free to share it with me:P
About return
:
Prelude> :t return
return :: (Monad m) => a -> m a
So return
takes an argument of type a
, and returns something of type m a
. In this case m
is LeafConType
, so LeafConType a
is returned.
Now suppose that we pass True
. Then a = Bool
, so the return type must be LeafConType Bool
. However, you define:
return = LeafCon
So, return True
becomes LeafCon True
. But that is not allowed, because the type definition of LeafConType
states that
data LeafConType a = LeafCon (a, Int, Int)
So for LeafConType Bool
the argument to LeafCon
must have type (Bool, Int, Int)
, not just Bool
. And that is what the compile error means: a
cannot be the same as (a, Int, Int)
. You state:
I want to do calculations while
i
is lower thann
.
This means that you will need some default values for i
and n
, for otherwise it will be impossible to define return
. If both of them are zero by default, then you could define:
return a = LeafCon (a, 0, 0)
About (>>=)
:
Prelude> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
Now look at your implementation (slightly different notation, same idea):
lc@(LeafCon (t, i, n)) >>= f | i >= n = lc
| otherwise = f t
What we see here, is that lc
is returned when i >= n
. But lc
is of type LeafConType a
, while f
is a function which may return a value of type LeafConType b
, for any b
. As a result it could be that b
is not equal to a
and hence these types don't match. In conclusion, you seriously have to ask yourself one question:
Can this type of computation be expressed as a monad anyway?
The functions you specified for >>=
and return
don't satisfy the types required by Monad
:
return :: a -> LeafConType a
Given the declaration
return = LeafCon
you give the function the incompatible type
return :: (a, Int, Int) -> LeafConType a
A statement like return 42
would therefore be impossible in your monad.
I don't understand what your monad should do at all. First take a look at simple, working monads!
instance Monad [] where
(>>=) = concatMap
return a = [a]
instance Monad Maybe where
return = Just
(Just x) >>= f = f x
Nothing >>= f = Nothing
Judging from your description of what you want your monad to do, I think you want something a bit like this:
data LeafConType a = LeafCon { runLeafCon' :: Int -> Int -> (Maybe a, Int, Int) }
runLeafCon :: Int -> Int -> LeafConType a -> Maybe a
runLeafCon i n lc = let (t, _, _) = runLeafCon' lc i n in t
getI :: LeafConType Int
getI = LeafCon $ \i n -> (Just i, i, n)
getN :: LeafConType Int
getN = LeafCon $ \i n -> (Just n, i, n)
setI :: Int -> LeafConType ()
setI i = LeafCon $ \_ n -> (Just (), i, n)
setN :: Int -> LeafConType ()
setN n = LeafCon $ \i _ -> (Just (), i, n)
instance Monad LeafConType where
return t = LeafCon $ \i n -> if (i < n)
then (Just t, i, n)
else (Nothing, i, n)
(LeafCon k) >>= f =
LeafCon $ \i n ->
let (t, i', n') = k i n
in case t of
Nothing -> (Nothing, i', n')
(Just t') -> if (i' < n')
then runLeafCon' (f t') i' n'
else (Nothing, i, n)
example :: Int -> LeafConType ((), Int)
example x = do
i <- getI
m <- setI (i + x)
return (m, i + x)
Some examples:
*Main> runLeafCon 2 10 $ example 4
Just ((),6)
*Main> runLeafCon 2 10 $ example 8
Nothing
*Main> runLeafCon 2 10 $ example 7
Just ((),9)
I threw this together pretty quickly, it's rather ugly, and I haven't checked to see whether it obeys any of the Monad laws, so use at your peril! :)
精彩评论