在haskell中创建单子
我想创建我自己的单子。这是我写的:在haskell中创建单子,haskell,monads,Haskell,Monads,我想创建我自己的单子。这是我写的: 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) 但这
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为
>=
和返回指定的函数不满足Monad
所需的类型:
return :: a -> LeafConType a
根据声明
return = LeafCon
您为函数指定了不兼容的类型
return :: (a, Int, Int) -> LeafConType a
因此,像return 42
这样的语句在monad中是不可能的
我根本不明白你的单子该怎么做。
首先看一看简单、有效的单子
instance Monad [] where
(>>=) = concatMap
return a = [a]
instance Monad Maybe where
return = Just
(Just x) >>= f = f x
Nothing >>= f = Nothing
关于返回
:
因此return
接受类型为a
的参数,并返回类型为ma
的内容。在本例中,m
是LeafConType
,因此返回LeafConType a
现在假设我们通过True
。然后a=Bool
,因此返回类型必须是LeafConType Bool
。但是,您可以定义:
return = LeafCon
因此,返回真值
变为LeafCon真值
。但这是不允许的,因为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)
关于(>>=)
:
现在看看您的实现(符号略有不同,想法相同):
我们在这里看到,lc
在i>=n
时返回。但是lc
属于leafcontypea
类型,而f
是一个函数,它可以为任何b
返回leafcontypeb
类型的值。结果可能是b
不等于a
,因此这些类型不匹配。总之,你必须认真地问自己一个问题:
这种类型的计算是否可以表示为monad?从您对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)
我很快就把它拼凑起来了,它相当难看,而且我还没有检查它是否遵守任何单子定律,所以使用它会有危险 我应该早10秒按下那个按钮…;)我认为可以,也许不是这样,但这是可能的。它应该携带诸如状态monad之类的信息,以及诸如monad之类的结束计算。您考虑过使用状态转换器吗。查看StateT
和error
。不要忘记MaybeT
Prelude> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
lc@(LeafCon (t, i, n)) >>= f | i >= n = lc
| otherwise = f t
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)