haskell中的嵌套/子数据类型



因此,如果您可以执行以下操作(不一定使用此格式,只是一般想法),那将是一件好事:

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

但现在你必须确保包装你的潜艇使用它们作为超级。。。再次不可怕;只是没有很好地表达我想要的语义(即Super可以是任何Sub或SuperB)。第一个(法律)例子是"Super可以是SubA…",第二个例子是"超级可以是接受Sub的SuperA…">

更改一些名称以避免与音乐混淆。

第页。S.从技术上讲,这始于我思考如何在Haskell中表示Scheme的数字塔。。。但我真的更感兴趣的是表示"Type1可以是Type2加x,y,…中的任何一个"这一更普遍的问题

这并不可怕,但它不能很好地扩展

如果您使用一些TemplateHaskell,那就好了。我会查看derive工具的makeIs例程以获得指导。

但现在你必须确保包装你的Subs,将其用作超级

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

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

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

你不能有像这样的东西

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

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

对于你的第二个例子,你的做法应该是默认的做法,但你可以做一个破解来让它更容易,尽管我不建议这样做,因为使用show要慢得多。你可以尝试其他类似的破解方法。

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

若你们真的想拥有像上面这样的东西,最好像你们一样定义函数。使用TH可能会帮你节省一些时间。

你的第三种情况是我真正建议你做的。您需要有一个像SuperA这样的包装构造函数,这是因为我在上面说过的原因。这就是为什么你不能精确地得到类型1是类型2加上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)。

您可能需要研究使用lens(Control.lens)库及其Data实例。数据和数据。可打字。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

最新更新