简体   繁体   English

haskell中的嵌套/子数据类型

[英]Nested/Sub data types in haskell

So what would be nice is if you could do something like the following (not necessarily with this format, just the general idea): 因此,如果您可以执行以下操作(不一定使用这种格式,只是一般思路),那将是一件好事:

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

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

So isSub SubA would report True (instead of an error.) At the moment you might do something like: 因此isSub SubA将报告True(而不是错误)。此刻,您可能会执行以下操作:

data Super = SubA | SubB | SuperB

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

It's not terrible or anything, but it doesn't expand nicely (as in if Sub when up to SubZ this would be terribly clunky) and it doesn't allow you to add the Sub types to their own type-class. 它并不可怕,也不是任何东西,但是它不能很好地扩展(例如,当Sub达到SubZ时,Sub会非常笨拙),并且不允许您将Sub类型添加到他们自己的类型类中。 To avoid that problem you can wrap Sub: 为了避免该问题,您可以包装Sub:

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

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

But now you have to make sure to wrap your Subs to use them as a Super... again not terrible; 但是现在您必须确保包装好Subs才能将它们用作Super ...再次并不可怕; just doesn't really express the semantics I'd like very well (ie Super can be any Sub or SuperB). 只是并没有真正很好地表达我想要的语义(即Super可以是任何Sub或SuperB)。 The first (legal) example is "Super can be SubA..." and the second is "Super can be SuperA that takes a Sub..." 第一个(合法)示例是“ Super可以是SubA ...”,第二个示例是“ Super可以是具有Sub ...的SuperA”。

EDTI: Change some names to avoid conflation with music stuff. EDTI:更改一些名称以避免与音乐混为一谈。

PS Technically, this started when I was thinking about how to represent Scheme's numeric tower in Haskell... but I'm really more interested in the more general issue of representing "Type1 can be any of Type2 plus x, y, ...) PS从技术上讲,这始于我正在考虑如何在Haskell中表示Scheme的数字塔...但是我对表示“ Type1可以是Type2加x,y,...中的任何一个……”这一更一般的问题更感兴趣。 )

It's not terrible or anything, but it doesn't expand nicely 它并不可怕,也不是什么,但扩展性不好

It would be fine if you used some Template Haskell. 如果您使用了一些模板Haskell,那就很好了。 I'd look at the derive tool's makeIs routine for guidance. 我看一下derive工具的makeIs例程作为指导。

But now you have to make sure to wrap your Subs to use them as a Super 但是现在您必须确保包装好Subs才能将它们用作Super

No, the type system will tell you if you forgot. 不,类型系统会告诉您是否忘记了。 For example, if you have 例如,如果您有

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

Then any context in which you use a Sub but expect a Super will be caught. 然后,将在您使用Sub但期望Super任何上下文中被捕获。 I'm guessing you already know that so did you mean something else? 我猜你已经知道了,所以你还有别的意思吗?

You can not have anything like 你不能有这样的事情

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

Suppose the above syntax is allowed, then the problem is given the value constructor SubA you can not tell whether its type is Sub or Super . 假设允许上面的语法,那么问题是给了值构造器SubA您无法分辨其类型是Sub还是Super That's why you need to wrap your type in a constructor. 这就是为什么需要将类型包装在构造函数中的原因。

For your second example, the way you are doing should be the default way of doing but you can do a hack to make it easier although I don't recommend doing this as using show is much slower. 对于第二个示例,您的操作方式应该是默认的操作方式,但是您可以进行破解以简化操作,尽管我不建议这样做,因为使用show的速度要慢得多。 You can try some other hack similar to this. 您可以尝试其他类似的技巧。

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

If you really want to have something like above it is better to define function like you did. 如果您真的想拥有上述类似的功能,最好像您一样定义函数。 Using TH might save you sometime. 使用TH可能会节省您一些时间。

Your third case is what I would really recommend doing. 您的第三种情况是我真正建议您做的。 You need to have a wrapper constructor like SuperA because of the reasons I told above. 由于我上面SuperA原因,您需要像SuperA这样的包装器构造函数。 That's why you can't have exactly type1 is of type2 plus x,y,z. 这就是为什么您不能完全让type1是type2加x,y,z的原因。 The closest thing you can have is to wrap elements in a constructor or using a typeclass. 您拥有的最接近的东西是将元素包装在构造函数中或使用类型类。

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

You can think here Super (which is a typeclass and not a type) contains Sub and someting extra ( Sup ). 您可以在这里认为Super (它是类型类而不是类型)包含Sub和someting extra( Sup )。

You might want to look into using the lens (Control.Lens) library with their instances for Data.Data and Data.Typleable. 您可能想研究将镜头(Control.Lens)库及其实例用于Data.Data和Data.Typleable。 Lens is an attempt to solve these type of multi level problems in lists, tuples and all other data types. 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 is really too general it checks to see if any of the children of the provided data type is of type Sub. isSub确实过于笼统,它会检查所提供数据类型的任何子级是否为Sub类型。 So if you had a tree and in the tree was a Sub then it would be True. 因此,如果您有一棵树,并且树上有一个Sub,那么它将为True。 It should be possible to restrict this to only your use case however. 但是,应该可以仅将其限制为您的用例。

The advantage of the Lens library is now I can add another layer to the type hierarchy. 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM