我正在尝试实现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’)
最正确的解决办法是什么?
答案 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)