代码之家  ›  专栏  ›  技术社区  ›  Mark Karavan

声明Monad时出现“No instance of Applicative”错误

  •  3
  • Mark Karavan  · 技术社区  · 9 年前

    我正在尝试实现 this paper ,如下所示:

    data Tree a = Fork (Tree a) (Tree a) | Leaf a | Nil deriving (Show)
    
    instance Monad Tree where
       return a = Leaf a
       Nil >>= f = Nil
       Leaf a >>= f = f a
       Fork u v >>= f = Fork (u >>= f) (v >>= f)
    
    tree1 = Fork 
             (Fork (Leaf 2) Nil) 
             (Fork (Leaf 2) (Leaf 3))
    
    tree2 = Fork (Leaf 2) (Leaf 3)
    
    f 2 = Fork Nil (Leaf "Two")
    f 3 = Fork (Leaf "Three") (Leaf "String")
    
    tree3 = tree2 >>= f
    

    当我在GHC中运行它时,我会得到以下错误:

    monads.hs:3:10:
        No instance for (Applicative Tree)
          arising from the superclasses of an instance declaration
        In the instance declaration for ‘Monad Tree’
    Failed, modules loaded: none.
    

    我试过在开头加上这个

    class Monad m where
        return :: a -> m a
        (>>=) :: m a -> (a -> m b) -> m b
    

    但我得到这个错误:

    monads.hs:7:10:
        Ambiguous occurrence ‘Monad’
        It could refer to either ‘Main.Monad’, defined at monads.hs:1:1
                              or ‘Prelude.Monad’,
                                 imported from ‘Prelude’ at monads.hs:1:1
                                 (and originally defined in ‘GHC.Base’)
    

    最正确的修复方法是什么?

    2 回复  |  直到 9 年前
        1
  •  11
  •   luqui    9 年前

    要扩展Louis Wasserman的评论,您需要添加 Applicative (因此 Functor )现在,当您声明 Monad 例子一旦您编写了 莫纳德 实例,其他实例始终相同:

    import Control.Monad (liftM, ap)
    
    instance Functor Tree where
        fmap = liftM
    instance Applicative Tree where 
        pure = return
        (<*>) = ap
    

    这改变了,因为每 莫纳德 是一个 适用性 (使用这个实例),但不是相反,所以从道义上讲它是一个超类。然而 适用性 在之后添加到标准库 莫纳德 所以它很长一段时间都没有成为一个真正的超类,因为这会破坏人们的代码。最近,自 适用性 社区决定 适用性 一个真正的超类 莫纳德 ,打破了每个人的代码一次,但为未来改进了它。这就是你看到的。

        2
  •  5
  •   willeM_ Van Onsem    9 年前

    问题是,就像 documentation 指定。这个 Monad 类签名为:

    class Applicative m => Monad m where
        --...
    

    这意味着为了将类型的实例定义为 莫纳德 ,首先需要将该类型定义为 Applicative 。自从 signature of Applicative 状态:

    class Functor f => Applicative f where
        --...
    

    所以你首先需要 Tree 的实例 Functor 在论文中,这是不必要的,因为据我所知,在早期版本的 Prelude 这些限制是不必要的。

    现在为了让它工作,我们首先 的实例 Functor函数 。因此,我们需要定义一个函数 fmap ,其中-对于给定函数 f :: a -> b ,映射a Tree a Tree b :

    instance Functor Tree where
       fmap f (Leaf a) = Leaf $ f a
       fmap f (Fork u v) = Fork (fmap f u) (fmap f v)
       fmap _ Nil = Nil
    

    既然我们已经定义了这个,我们可以定义 适用性 :

    instance Applicative Tree where
        pure = Leaf
        (<*>) (Leaf f) = fmap f
        (<*>) Nil = const $ Nil
    

    最后我们可以定义 莫纳德 实例:

    instance Monad Tree where
       return a = Leaf a
       Nil >>= f = Nil
       Leaf a >>= f = f a
       Fork u v >>= f = Fork (u >>= f) (v >>= f)