【问题标题】:Creating monads in haskell在 haskell 中创建 monad
【发布时间】:2009-11-22 17:58:35
【问题描述】:

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

【问题讨论】:

    标签: haskell monads


    【解决方案1】:

    关于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 BoolLeafCon 的参数必须具有(Bool, Int, Int) 类型,而不仅仅是Bool。这就是编译错误的含义:a 不能与(a, Int, Int) 相同。你说:

    我想在i 低于n 时进行计算。

    这意味着您将需要in 的一些默认值,否则将无法定义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 时返回。但是lcLeafConType a 类型,而f 是一个函数,对于any b,它可能返回一个LeafConType b 类型的值。因此,b 可能不等于 a,因此这些类型不匹配。总之,您必须认真地问自己一个问题:

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

    【讨论】:

    • 我认为可以,也许不是这样,但有可能。它应该携带像 State monad 这样的信息,以及像 Maybe monad 这样的结束计算。
    • 您考虑过使用状态转换器吗? en.wikibooks.org/wiki/Haskell/Monad_transformers。看看StateTErrorT
    • 别忘了MaybeT
    【解决方案2】:

    您为>>=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
    

    【讨论】:

    • 我应该早 10 秒按下那个按钮... ;)
    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-07-26
      • 1970-01-01
      • 1970-01-01
      • 2018-03-15
      • 1970-01-01
      • 2015-04-22
      • 2019-01-23
      相关资源
      最近更新 更多