鉴于Free Monad
:
data Free f a = Var a
| Node (f (Free f a))
我尝试为它定义一个Eq
实例:
instance (Functor f, Eq (f a)) => Eq (Free f a) where
(==) (Var x) (Var y) = x == y
(==) (Node fu1) (Node fu2) = fu1 == fu2
(==) _ _ = False
但是无法编译:
FreeMonad.hs:17:10:
Non type-variable argument in the constraint: Eq (f a)
(Use FlexibleContexts to permit this)
In the context: (Functor f, Eq (f a))
While checking an instance declaration
In the instance declaration for ‘Eq (Free f a)’
Failed, modules loaded: none.
指定(Functor f, Eq (f a))
的约束/前提条件对我来说似乎很奇怪(至少我认为我之前没有把它视为初学者)。
如何为Eq
定义Free f a
个实例?
答案 0 :(得分:11)
拥有像Eq (f a)
这样的约束没有错。正如错误消息所示,您需要启用(无害的)FlexibleContexts
GHC扩展来执行此操作,因此请添加...
{-# LANGUAGE FlexibleContexts #-}
...到源文件的顶部。
但请注意,(Functor f, Eq (f a))
并未真正反映您在实施(==)
时所做的工作。首先,您不需要f
这里是Functor
的假设,因此您可以安全地删除Functor f
约束。其次,约束应该与您编写不同情况所需的内容相匹配。在第一种情况下,您执行x == y
。 x
和y
都属于a
类型,因此您需要Eq a
。出于类似的原因,第二种情况需要Eq (f (Free f a))
而不是Eq (f a)
。这意味着你最终将会......
(Eq (f (Free f a)), Eq a) => Eq (Free f a)
...匹配参考实现,例如Control.Monad.Free
中的参考实现。
答案 1 :(得分:2)
duplode展示了如何使用灵活的上下文来完成它。如果您想要Haskell 2010,通常的方法是使用Eq1
中的Prelude.Extras
类或类似的。
class Eq1 f where
(==#) :: Eq a => f a -> f a -> Bool
然后你会用
instance (Eq1 f, Eq a) => Eq (Free f a) where ...
instance Eq1 f => Eq1 (Free f) -- default instance is fine.
我现在不在我的电脑上,所以直到以后才能测试。