1

因此,如果您可以执行以下操作(不一定使用这种格式,只是一般的想法),那就太好了:

data Sub = SubA | SubB
data Super = Sub | SuperB

isSub :: Super -> Bool
isSub Sub = True
isSub _ = False

所以 isSub SubA 会报告 True (而不是错误。)此刻你可能会做类似的事情:

data Super = SubA | SubB | SuperB

isSub :: Super -> Bool
isSub SubA = True
isSub SubB = True
isSub _ = False

它并不可怕或任何东西,但它不能很好地扩展(就像 Sub 到 SubZ 时这将非常笨重)并且它不允许您将 Sub 类型添加到它们自己的类型类中。为避免该问题,您可以包装 Sub:

data Sub = SubA | SubB
data Super = SuperA Sub | SuperB

isSub :: Super -> Bool
isSub (SuperA _) = True
isSub _ = False

但是现在您必须确保将您的 Subs 包装起来以将它们用作 Super... 再次不可怕;只是并没有真正表达出我想要的语义(即 Super 可以是任何 Sub 或 SuperB)。第一个(合法)示例是“Super 可以是 SubA...”,第二个是“Super 可以是带有 Sub...的 SuperA”

EDTI:更改一些名称以避免与音乐内容混为一谈。

PS 从技术上讲,这开始于我在考虑如何在 Haskell 中表示 Scheme 的数字塔......但我真的对表示“Type1 可以是 Type2 加 x、y、...... )

4

3 回答 3

1

它并不可怕或任何东西,但它不能很好地扩展

如果你使用一些 Template Haskell 就好了。我会查看该derive工具的makeIs例程以获取指导。

但是现在你必须确保包装你的 Subs 以将它们用作 Super

不,如果您忘记了,类型系统会告诉您。例如,如果您有

data Super = Sub Sub | Super
data Sub = SubA | SubB

然后将捕获您使用 aSub但期望 a 的任何上下文。Super我猜你已经知道了,所以你的意思是别的吗?

于 2012-12-17T06:43:28.190 回答
0

你不能有类似的东西

data Sub = SubA | SubB
data Super = Sub | SuperB

假设上面的语法是允许的,那么问题是给定值构造函数SubA你无法判断它的类型是Sub还是Super。这就是为什么您需要将类型包装在构造函数中的原因。

对于您的第二个示例,您正在执行的方式应该是默认的执行方式,但是您可以进行 hack 以使其更容易,尽管我不建议这样做,因为使用 show 会慢得多。您可以尝试其他类似的 hack。

import Data.List
data Super = SubA | SubB | SuperB deriving Show
isSub :: Super -> Bool
isSub m = isPrefixOf "Sub" (show m)

如果你真的想要上面的东西,最好像你一样定义函数。使用 TH 可能会节省您的时间。

你的第三种情况是我真正建议做的。SuperA由于我上面所说的原因,您需要有一个包装器构造函数。这就是为什么你不能完全确定 type1 是 type2 加上 x,y,z 的原因。您可以拥有的最接近的方法是将元素包装在构造函数中或使用类型类。

data Sub = SubA | SubB
data Sup = SuperA | SuperB

class Super a where
  isSub :: a -> Bool
  isSub _ = True

instance Super Sup where
    isSub _ = False

instance Super Sub

data SupSup = SuperSuperA | SuperSuperB

class SuperSuper a where
    isSuper :: a -> Bool
    isSuper _ = True


instance SuperSuper SupSup where
    isSuper _ = False

instance SuperSuper Sup
instance SuperSuper Sub

你可以认为这里Super(它是一个类型类而不是一个类型)包含Sub和一些额外的(Sup)。

于 2012-12-17T06:45:47.257 回答
0

您可能想考虑使用镜头 (Control.Lens) 库及其 Data.Data 和 Data.Typleable 实例。Lens 试图在列表、元组和所有其他数据类型中解决这些类型的多层次问题。

>data Sub =  SubA | SubB deriving (Show, Data, Typeable, Eq)
>data Super =  SuperA Sub | SuperB deriving (Show, Data, Typeable, Eq)

-- A little bit of a hack, there is probably a better way of doing this
>isSub' :: Sub -> Bool
>isSub' x = typeOf x == typeOf SubA

>tmp1 = SuperA SubA
>tmp2 = SuperA SubB

>isSub x = anyOf biplate (isSub') x

>isSub tmp1
True
>issub tmp2
True

isSub 实在是太笼统了,它会检查所提供数据类型的任何子项是否属于 Sub 类型。因此,如果您有一棵树,并且树中有一个 Sub,那么它就是 True。但是,应该可以将其仅限于您的用例。

Lens 库的优点是现在我可以在类型层次结构中添加另一层。

>data SuperSuper =  SuperSuperA Super | SuperSuperB | SuperSuperC Sub deriving (Show,Data,Typeable)

>tmp3 = SuperSuperA (SuperA SubA)
>tmp4 = SuperSuperC SubB

>isSub tmp3
True
>isSub tmp4
True
于 2013-01-03T01:40:48.473 回答