首页 > 解决方案 > 定义枚举子类型不是序数的序数类型

问题描述

我遇到了定义其值可能是也可能不是序数的序数类型的问题。

基本上我有两种类型,一个OrderedType和一个UnorderedType

data OrderedType = One | Two | Three deriving (Eq, Ord, Show)
data UnorderedType = Red | Blue | Green deriving (Eq, Show)

我有一个类型,其值构造函数将任何一个作为参数:

data WrapperType = WrappedOne OrderedType
                   | WrappedTwo UnorderedType deriving (Eq, Ord, Show)

基本上,我想要做的是WrapperType无需为and实现compare函数即可订购 s 。WrappedOneWrappedTwo

当我尝试编译上述内容时,出现以下错误:

• No instance for (Ord UnorderedType)
arising from the first field of ‘WrappedTwo’ (type ‘UnorderedType’)
Possible fix:
use a standalone 'deriving instance' declaration,
  so you can specify the instance context yourself
• When deriving the instance for (Ord WrappedType)

这是有道理的,因为股票派生Ord实例WrappedType将尝试比较 的所有值WrappedTwo

简而言之,我想要做的是:

WrappedOne _ < WrappedTwo _ -- True

Ord但是没有为每种类型编写一个实例。

我该怎么做呢?

标签: haskell

解决方案


不是 100% 清楚你想要什么;我猜你希望所有构造的值WrappedTwo都被认为是等效的?

newtype ForgetOrder a = ForgetOrder a

instance Eq (ForgetOrder a) where
    _ == _ = True

instance Ord (ForgetOrder a) where
    compare _ _ = EQ

然后您可以将您的类型定义为:

data WrapperType = WrappedOne OrderedType
                 | WrappedTwo (ForgetOrder UnorderedType) deriving (Eq, Ord, Show)

是的,必须包装和打开新类型有点麻烦,并且编写模式同义词来避免它也很麻烦。这就是生活。

但是,我担心你也想要WrappedTwo Red /= WrappedTwo Green。在这一点上,我将不得不与瓦格纳先生一起赶上潮流,并说,无论你正在穿越的思想路径需要这个,转身寻找另一种方式。Haskell 的一大乐趣是人们关心法律[1]。你会发现在 Hackage 上定义违法实例的库很少。并且有充分的理由:例如,Data.Set期望Ord定义一个总订单并与Eq. 具有违法行为的类型Ord使Set该类型的 a 完全荒谬和破坏。但我自信地把各种东西放在Sets 中,世界上没有任何担忧,因为合法性在 Haskell 文化中无处不在。

但是,如果您不这么认为……很好。抱歉说教。


[1] 我很尴尬地发现课程中没有记录Ord预期的法律。无论如何,我对这些法律的传统理解如下:

  1. 等价符号:

    x < y   =  compare x y == LT
    x > y   =  compare x y == GT
    x == y  =  compare x y == EQ
    x <= y  =  x < y || x == y
    x >= y  =  x > y || x == y
    
  2. ==是等价关系:

    x == x
    If x == y then y == x
    If x == y and y == z then x == z
    
  3. ==可扩展 性(这个似乎比其他的要宽松一些;例如,可能不是可扩展的sort前提的文档):==

    if x == y, then f x == f y
    

    (对于可以从给定抽象边界之外定义的 f;IOW 允许相同值的不同表示,只要用户无法区分它们。)

  4. 总数<

    If x <= y  and  y <= z  then x <= z
    

    (三分法来自“符号等价”和比较)


推荐阅读