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