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

Getting a "No instance of Applicative" error when declaring a Monad

我正在尝试实现 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’)

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

要扩展 Louis Wasserman 的评论,您现在需要在声明 Monad 实例时添加一个 Applicative(因此 Functor)实例。一旦你编写了 Monad 实例,其他实例总是相同的:

import Control.Monad (liftM, ap)

instance Functor Tree where
    fmap = liftM
instance Applicative Tree where 
    pure = return
    (<*>) = ap

这改变了,因为每个 Monad 都是一个 Applicative(使用这个实例),但不是相反,所以它在道德上是一个超类。但是,ApplicativeMonad 之后被添加到标准库中,因此很长一段时间内它都没有成为真正的超类,因为这会破坏人们的代码。最近,由于 Applicative 的使用非常普遍,社区决定让 Applicative 成为 Monad 的真正超类,一次打破每个人的代码,但为了将来改进它。这就是您所看到的。

问题是,就像documentation指定的那样。 Monad class 签名是:

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

这意味着为了将类型的实例定义为Monad,您首先需要将该类型定义为Applicative。由于 signature of Applicative 状态,问题更加严重:

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

所以你首先需要让Tree成为Functor的一个实例。在本文中,这不是必需的原因是 - 据我所知,在 Prelude 的早期版本中,这些约束是不必要的。

现在为了让它工作,我们首先让Tree成为Functor的一个实例。因此,我们需要定义一个函数 fmap,它 - 对于给定的函数 f :: a -> b,将 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

现在我们已经定义了这个,我们可以定义Applicative:

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

最后我们可以定义 Monad 实例:

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)