【发布时间】:2017-01-16 18:51:19
【问题描述】:
是否可以使用 GHC 扩展来定义一个新的类型类来泛化为任意长度的元组?
关于 Prelude 和 Base 中内置类的行为(有些类支持多达 15 个元素的元组,有些多达 7 个)以及扩展这些类的(非)可能性,已经存在一些问题。
前奏和基本行为: Haskell Tuple Size Limit
用新定义扩展 Show: Extend a Show instance to a Tuple of any size
我问的是一个稍微不同的问题。如果我正在制作一个全新的类型类,是否可以添加一个实例规则来处理任意长度的元组(可能使用 GHC 扩展)?
这是一个名为 PartialOrder 的类的示例。我想允许使用以下规则对任意大小的元组进行部分比较
(a,b ... , z) <= (a1,b1, ... , z1) iff (a <= a1) && (b <= b1) && ... && (z <= z1)
这是我第一次尝试使用传统的“为不超过任意大小的元组定义类”方法进行定义。
是否有可用于编写涵盖任意长度元组的实例定义的 GHC 扩展?
我想我可以使用 Template Haskell 或外部程序提前生成定义,但不能像 C++ 模板那样按需生成。
-- Sets equipped with the (is_subset) operation are an example of a
-- partial order.
--
-- {} < {a} less than
-- {} = {} equal to
-- {a, b} > {b} greater than
-- {a} ~ {b} incomparable
--
-- in order to define a partial order we need a definition of (<=)
data PartialOrdering = POLessThan | POGreaterThan | POEqual | POIncomparable deriving (Eq, Show)
class PartialOrder a where
lessThanEq :: a -> a -> Bool
instance PartialOrder PartialOrdering where
lessThanEq POIncomparable _ = False
lessThanEq _ POIncomparable = False
-- with incomparables dealt with...
lessThanEq POLessThan _ = True
lessThanEq POEqual POLessThan = False
lessThanEq POEqual _ = True
lessThanEq POGreaterThan POGreaterThan = True
lessThanEq POGreaterThan _ = False
-- note this is different from the semantics for Ord applied to tuples,
-- which uses lexicographic ordering.
--
-- (a,b) is less than or equal to (c,d) iff
-- a <= b and c <= d
-- 2 element tuple
instance (PartialOrder a, PartialOrder b) => PartialOrder (a, b) where
lessThanEq (a,b) (c,d) = (lessThanEq a c) && (lessThanEq b d)
-- 3 element tuple
instance (PartialOrder a, PartialOrder b, PartialOrder c) => PartialOrder (a, b, c) where
lessThanEq (a,b,c) (d,e,f) = (lessThanEq a d) && (lessThanEq b e) && (lessThanEq c f)
-- 4 element tuple
instance (PartialOrder a, PartialOrder b, PartialOrder c, PartialOrder d) => PartialOrder (a, b, c, d) where
lessThanEq (a,b,c,d) (e,f,g,h) = (lessThanEq a e) && (lessThanEq b f) && (lessThanEq c g) && (lessThanEq d h)
-- etc.
main = putStrLn "hi"
【问题讨论】:
-
只是一个建议:为什么不使用长度索引列表?这种数据类型与元组同构。使用 GADT 很容易定义它。
标签: haskell