是否可以使用GHC扩展来定义一个新的类型,它可以推广到任意长度的元组?
已经有一些关于Prelude和Base中内置类的行为的问题(一些类支持多达15个元素的元组,有些类最多支持7个元素)以及扩展这些类的(非)可能性。 / p>
Prelude和Base行为: 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)
这是我第一次尝试使用传统的定义#34;将元组定义为任意大小的元组&#34;方法
是否有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"
答案 0 :(得分:4)
Haskell中的元组类型并没有真正相互了解。值得庆幸的是,对于您的特定情况,您可以使用GHC.Generics
解决您的问题。然后,您实际上可以为任何产品类型派生PartialOrder
类,而不仅仅是元组。
{-# LANGUAGE TypeOperators, DefaultSignatures, FlexibleContexts,
StandaloneDeriving, DeriveAnyClass
#-}
import GHC.Generics
import Data.Function (on)
data PartialOrdering
= POLessThan | POGreaterThan | POEqual | POIncomparable deriving (Eq, Show)
class PartialOrder a where
lessThanEq :: a -> a -> Bool
default lessThanEq :: (Generic a, GPartialOrder (Rep a)) => a -> a -> Bool
lessThanEq = gLessThanEq `on` from
-- | Helper generic version of your class
class GPartialOrder f where
gLessThanEq :: f a -> f a -> Bool
-- | Product types
instance (GPartialOrder a, GPartialOrder b) => GPartialOrder (a :*: b) where
gLessThanEq (a1 :*: b1) (a2 :*: b2) = gLessThanEq a1 a2 && gLessThanEq b1 b2
-- | Unary type (empty product)
instance GPartialOrder U1 where
gLessThanEq U1 U1 = True
-- | Meta information on type
instance (GPartialOrder a) => GPartialOrder (M1 i c a) where
gLessThanEq (M1 a1) (M1 a2) = gLessThanEq a1 a2
-- | Single type
instance (PartialOrder a) => GPartialOrder (K1 i a) where
gLessThanEq (K1 x1) (K1 x2) = lessThanEq x1 x2
完成所有设置后,如果派生-XDeriveAnyClass
(可以使用Generic
完成),则可以自动派生您的课程(启用-XDeriveGeneric
)。元组类型已经是泛型的实例,因此使用-XStandaloneDeriving
,您可以反向主动派生Partial Order
的实例。所有以下工作
deriving instance (PartialOrder a, PartialOrder b) => PartialOrder (a,b)
deriving instance (PartialOrder a, PartialOrder b, PartialOrder c) => PartialOrder (a,b,c)
-- and so on...
data MyProduct a b = MyProduct a b deriving (Generic, PartialOrder)
之后,您可以按预期使用您的课程:
ghci> (POLessThan, POLessThan) `lessThanEq` (POEqual, POEqual)
True
ghci> (POLessThan, POEqual) `lessThanEq` (POEqual, POEqual)
True
ghci> (POLessThan, POEqual) `lessThanEq` (POEqual, POLessThan)
False