Haskell 具有实例定义的新类型类在任何长度的元组上都是泛型的

Haskell 具有实例定义的新类型类在任何长度的元组上都是泛型的,haskell,Haskell,是否可以使用GHC扩展来定义一个新的类型类,该类可以泛化为任意长度的元组 关于Prelude和Base中内置类的行为(有些类支持多达15个元素元组,有些支持多达7个元素元组)以及扩展这些类的可能性(非)已经有一些问题 前奏和基本动作: 使用新定义扩展Show: 我在问一个稍微不同的问题。如果我正在创建一个全新的类型类,是否可以添加一个处理任意长度元组的实例规则(可能使用GHC扩展) 下面是一个名为PartialOrder的类的示例。我想使用以下规则允许对任意大小的元组进行部分比较 (a,b

是否可以使用GHC扩展来定义一个新的类型类,该类可以泛化为任意长度的元组

关于Prelude和Base中内置类的行为(有些类支持多达15个元素元组,有些支持多达7个元素元组)以及扩展这些类的可能性(非)已经有一些问题

前奏和基本动作:

使用新定义扩展Show:

我在问一个稍微不同的问题。如果我正在创建一个全新的类型类,是否可以添加一个处理任意长度元组的实例规则(可能使用GHC扩展)

下面是一个名为PartialOrder的类的示例。我想使用以下规则允许对任意大小的元组进行部分比较

(a,b ... , z) <= (a1,b1, ... , z1) iff (a <= a1) && (b <= b1) && ... && (z <= z1)

(a,b…,z)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
通过所有这些设置,如果您派生
泛型
(可以使用
-XDeriveGeneric
完成),则可以自动派生您的类(启用
-xderivanyclass
)。元组类型已经是泛型的实例,因此使用
-XStandaloneDeriving
,您可以逆向地派生
偏序的实例。以下所有工作

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

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
通过所有这些设置,如果您派生
泛型
(可以使用
-XDeriveGeneric
完成),则可以自动派生您的类(启用
-xderivanyclass
)。元组类型已经是泛型的实例,因此使用
-XStandaloneDeriving
,您可以逆向地派生
偏序的实例。以下所有工作

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

只是一个建议:为什么不使用长度索引列表?这样的数据类型与元组同构。使用GADT定义它很容易。只是一个建议:为什么不使用长度索引列表?这样的数据类型与元组同构。使用GADT很容易定义它。