11

我想创建自己的 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'

那有什么问题?


我想在 i 小于 n 时进行计算。n 应该是常数,因为我还不知道如何正确地做到这一点。它应该是 State 和 Maybe 的某种混合。如果你有一些建议,请随时与我分享:P

4

3 回答 3

13

关于return

Prelude> :t return
return :: (Monad m) => a -> m a 

所以return接受一个类型的参数a,并返回一些类型的东西m a。在这种情况下mLeafConType,所以LeafConType a返回。

现在假设我们通过True. 那么a = Bool,所以返回类型必须是LeafConType Bool。但是,您定义:

return = LeafCon

所以,return True变成LeafCon True。但这是不允许的,因为类型定义LeafConType声明

data LeafConType a = LeafCon (a, Int, Int)

所以对于LeafConType Bool参数 toLeafCon必须有类型(Bool, Int, Int),而不仅仅是Bool. 这就是编译错误的含义:a不能与(a, Int, Int). 你说:

我想在i低于n.

这意味着您需要为iand设置一些默认值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

我们在这里看到的是,lci >= n. Butlc是 type 的LeafConType a,whilef是一个函数,它可以返回一个 type 的值LeafConType b,对于any b。因此,它可能b不等于a,因此这些类型不匹配。总之,你必须认真地问自己一个问题:

  这种类型的计算无论如何都可以表示为单子吗?

于 2009-11-22T18:17:03.323 回答
7

您指定>>=return不满足以下要求的类型的函数Monad

return :: a -> LeafConType a

鉴于声明

return = LeafCon

你给函数不兼容的类型

return :: (a, Int, Int) -> LeafConType a

return 42因此,在您的 monad 中不可能有这样的陈述。

我根本不明白你的 monad 应该做什么。首先看一下简单的工作单子!

instance Monad [] where
    (>>=) = concatMap
    return a = [a]

instance Monad Maybe where
    return = Just
    (Just x) >>= f = f x
    Nothing >>= f = Nothing
于 2009-11-22T18:16:52.943 回答
4

从你对你想让你的 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 定律,所以使用后果自负!:)

于 2009-11-23T12:16:46.073 回答