我有一个带有相当多构造函数的数据类型,所有这些都很简单,Haskell可以自动派生Ord实例。如:
data Foo a
= A a
| B Int
deriving (Eq, Ord)
现在我想添加第三个构造函数:
data Foo a
= A a
| B Int
| C a (a -> Bool)
但是现在Haskell无法为我Eq
手动派生Ord
和Foo
。现在,碰巧我有一些关于如何使用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情况下进行比较,但不知何故得到"默认"其他构造函数的行为?
答案 0 :(得分:5)
您可以使用特殊情况的类型参数化Foo
,然后分别为newtypes实现特殊实例:
data Foo' c a
= A a
| B Int
| C (c a)
deriving (Eq, Ord)
data C a = MkC a (a -> Bool)
instance Eq a => Eq (C a) where
MkC x f == MkC y g = x == y && f x == g y
instance Ord a => Ord (C a) where
MkC x f `compare` MkC y g
| x == y = f x `compare` g y
| otherwise = x `compare` y
type Foo = Foo' C
答案 1 :(得分:3)
这个"包"函数的一个参数(称为Store
comonad(..没有Eq
实例))可以是你寻求的Eq
和Ord
的实例/ p>
data Store s a = Store (s -> a) s
instance (Eq s, Eq a) => Eq (Store s a) where
(==) :: Store s a -> Store s a -> Bool
Store f s == Store f' s' =
(s == s')
&&
(f s == f' s')
instance (Ord s, Ord a) => Ord (Store s a) where
compare :: Store s a -> Store s a -> Ordering
Store f s `compare` Store f' s' =
(compare s s')
<>
(f s `compare` f' s')
现在,您可以导出Eq
和Ord
data Foo a
= A a
| B Int
| C (Store a Bool)
deriving (Eq, Ord)
答案 2 :(得分:2)
由于您对这些功能有所了解,因此请考虑将有关该功能的信息存储起来,并在必要时重新解释为功能。例如,也许您所知道的是它们是部分应用的(<)
;那样的话:
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
data Foo a
= A a
| B Int
| C_ a a
deriving (Eq, Ord, Read, Show)
pattern C a f <- C_ a ((<) -> f)
当然,如果你有一种比仅添加更复杂的表达式语言,你可能想要为AST定义一个单独的类型,以及一个用于评估AST的单独函数;但AST本身应该在大多数简单的情况下,你提出的比较规则是正确的,可以相等/可订购。