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

时间:2016-01-06 19:33:09

标签: haskell types monads

我正在尝试实现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 个答案:

答案 0 :(得分:8)

要扩展Louis Wasserman的评论,您需要在声明Applicative实例时添加Functor(因此Monad)实例。编写Monad实例后,其他实例始终相同:

import Control.Monad (liftM, ap)

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

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

答案 1 :(得分:5)

问题在于,就像documentation指定的一样。 Monad类签名是:

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)