声明 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
(使用这个实例),但不是相反,所以它在道德上是一个超类。但是,Applicative
在 Monad
之后被添加到标准库中,因此很长一段时间内它都没有成为真正的超类,因为这会破坏人们的代码。最近,由于 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)
我正在尝试实现 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
(使用这个实例),但不是相反,所以它在道德上是一个超类。但是,Applicative
在 Monad
之后被添加到标准库中,因此很长一段时间内它都没有成为真正的超类,因为这会破坏人们的代码。最近,由于 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)