【发布时间】:2018-01-28 14:47:31
【问题描述】:
我有一个包含很多构造函数的数据类型,所有构造函数都很简单,Haskell 可以自动派生 Ord 实例。如:
data Foo a
= A a
| B Int
deriving (Eq, Ord)
现在我想像这样添加第三个构造函数:
data Foo a
= A a
| B Int
| C a (a -> Bool)
但现在 Haskell 不能为我手动推导出 Foo 上的 Eq 和 Ord。现在,碰巧我对如何对使用C 构造的两个值进行排序有了一些特定领域的知识:
instance Eq a => Eq (Foo a) where
-- Boilerplate I don't want to write
A x == A y = x == y
B x == B y = x == y
-- This is the case I really care about
C x f == C y g = x == y && f x == g y
_ == _ = False
instance Ord a => Ord (Foo a) where
-- Boilerplate I don't want to write
A x `compare` A y = x `compare` y
A x `compare` _ = LT
B x `compare` B y = x `compare` y
B x `compare` A _ = GT
B _ `compare` _ = LT
-- This is the case I really care about
C x f `compare` C y g
| x == y = f x `compare` g y
| otherwise = x `compare` y
C{} `compare` _ = GT
但为了做到这一点,我还必须手动实现对 A 和 B 值的排序,这确实很繁琐(尤其是对于 Ord 实例)。
是否有任何技巧可以让我实现 (==) 并仅在 C 情况下进行比较,但以某种方式在其他构造函数上获得“默认”行为?
【问题讨论】:
-
只需给
a -> Bool一个手动的Ord实例(但最好先将它包装在newtype中)。 -
说得好!
-
很抱歉,根据您的情况,我认为您需要一些更复杂的东西:创建一个
data X a = X a (a->Bool),使其成为Ord并使用... | C X。
标签: haskell typeclass algebraic-data-types