为免费Monad定义平等实例

时间:2015-09-20 02:34:50

标签: haskell equality

鉴于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个实例?

2 个答案:

答案 0 :(得分:11)

拥有像Eq (f a)这样的约束没有错。正如错误消息所示,您需要启用(无害的)FlexibleContexts GHC扩展来执行此操作,因此请添加...

{-# LANGUAGE FlexibleContexts #-}

...到源文件的顶部。

但请注意,(Functor f, Eq (f a))并未真正反映您在实施(==)时所做的工作。首先,您不需要f这里是Functor的假设,因此您可以安全地删除Functor f约束。其次,约束应该与您编写不同情况所需的内容相匹配。在第一种情况下,您执行x == yxy都属于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.

我现在不在我的电脑上,所以直到以后才能测试。