题
我要创造我自己的单子。这是我写的:
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'
请告诉我错?
我想要做的计算而i为低于n。 N乘我应该是常数,还不知道如何做到这一点是正确的。它应该是一些混合的国家,也许。如果你有一些建议随时与我分享吧:P
解决方案
关于return
:
Prelude> :t return
return :: (Monad m) => a -> m a
所以return
采用类型a
的参数,并返回型m a
的东西。在这种情况下是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
和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
我们在这里看到的是什么,是lc
返回时i >= n
。但lc
是类型LeafConType a
,而f
为可返回式的LeafConType b
的值,任何 b
的功能。因此,它可能是b
不等于a
,因此这些类型不匹配。总之,你真的要问自己一个问题:
<强> 能这种类型的计算反正表示为单子? 强>
其他提示
你>>=
和return
不满足类型中指定的功能所需要的由Monad
:
return :: a -> LeafConType a
鉴于声明
return = LeafCon
你给该函数的不兼容的类型
return :: (a, Int, Int) -> LeafConType a
像return 42
声明将因此会不可能在你的单子。
我不明白你的单子应该不惜一切做什么。 先来看看简单,工作单子!
instance Monad [] where
(>>=) = concatMap
return a = [a]
instance Monad Maybe where
return = Just
(Just x) >>= f = f x
Nothing >>= f = Nothing
从你的你希望你的单子做什么的描述来看,我觉得你想要的东西有点像这样:
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)
我把这个在一起很快,这是相当丑陋,我还没有检查,看它是否服从任何的单子法律,所以在使用后果自负! :)