为免费 Monad 定义平等实例
Define Equality Instance for Free Monad
鉴于 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))
的 constraint/pre-condition 对我来说似乎很奇怪(至少我不认为我以前作为初学者见过它)。
如何为 Free f a
定义 Eq
实例?
像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
.
中的参考实现
duplode 展示了如何使用灵活的上下文来做到这一点。如果你想要 Haskell 2010,通常的方法是使用 Prelude.Extras
或类似的 Eq1
class。
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.
我现在不在电脑旁,所以我要等会儿才能测试这个。
鉴于 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))
的 constraint/pre-condition 对我来说似乎很奇怪(至少我不认为我以前作为初学者见过它)。
如何为 Free f a
定义 Eq
实例?
像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
.
duplode 展示了如何使用灵活的上下文来做到这一点。如果你想要 Haskell 2010,通常的方法是使用 Prelude.Extras
或类似的 Eq1
class。
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.
我现在不在电脑旁,所以我要等会儿才能测试这个。