[英]Creating monads in haskell
我想创建自己的monad。 这就是我写的:
data LeafConType a = LeafCon (a,Int,Int)
instance Monad (LeafConType ) where
return = LeafCon
lc@(LeafCon (t,i,n)) >>= f = if i>=n
then lc
else f (t,i,n)
但这不行。 Ghc说:
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'
那有什么不对吗?
当我低于n时,我想做计算。 n应该是常数我还不知道如何做到这一点。 它应该是State和Maybe的混合体。 如果您有任何建议,请随时与我分享:P
return
: Prelude> :t return
return :: (Monad m) => a -> m a
因此, return
需要类型的参数a
,并返回一个类型的东西ma
。 在这种情况下, m
是LeafConType
,因此返回LeafConType a
。
现在假设我们传递了True
。 然后a = Bool
,所以返回类型必须是LeafConType Bool
。 但是,您定义:
return = LeafCon
所以, return True
成为LeafCon True
。 但是这是不允许的,因为LeafConType
的类型定义表明了这一点
data LeafConType a = LeafCon (a, Int, Int)
因此,对于LeafConType Bool
的参数LeafCon
必须有类型(Bool, Int, Int)
而不仅仅是Bool
。 这就是编译错误的含义: a
不能与(a, Int, Int)
。 你说:
当
i
低于n
时,i
想做计算。
这意味着您将需要i
和n
一些默认值,否则将无法定义return
。 如果默认情况下它们都为零,那么您可以定义:
return a = LeafCon (a, 0, 0)
(>>=)
: Prelude> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
现在看看你的实现(略有不同的表示法,相同的想法):
lc@(LeafCon (t, i, n)) >>= f | i >= n = lc
| otherwise = f t
我们在这里看到的是,当i >= n
时返回lc
。 但lc
的类型为LeafConType a
,而f
是一个函数,可以为任何 b
返回LeafConType b
类型的值。 结果可能是b
不等于a
,因此这些类型不匹配。 总之,你真的要问自己一个问题:
这种类型的计算是否可以表示为monad?
您为>>=
和return
指定的函数不满足Monad
所需的类型:
return :: a -> LeafConType a
鉴于声明
return = LeafCon
你赋予函数不兼容的类型
return :: (a, Int, Int) -> LeafConType a
因此, return 42
这样的陈述在你的monad中是不可能的。
我不明白你的monad应该做什么。 首先来看看简单,有效的monad!
instance Monad [] where
(>>=) = concatMap
return a = [a]
instance Monad Maybe where
return = Just
(Just x) >>= f = f x
Nothing >>= f = Nothing
从您对monad要做的事情的描述来看,我认为你想要的东西有点像这样:
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)
一些例子:
*Main> runLeafCon 2 10 $ example 4
Just ((),6)
*Main> runLeafCon 2 10 $ example 8
Nothing
*Main> runLeafCon 2 10 $ example 7
Just ((),9)
我很快把它扔在一起,它相当丑陋,而且我没有检查它是否符合任何Monad定律,所以使用你的危险! :)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.