haskell中的嵌套/子数据类型

时间:2012-12-17 05:01:13

标签: haskell abstract-data-type

那么,如果你可以做类似下面的事情(不一定是这种格式,只是一般的想法),那会更好:

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)。第一个(合法的)例子是“超级可以是SubA ......”,第二个是“超级可以超级采用Sub ...”

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

P.S。从技术上讲,这是在我考虑如何在Haskell中表示Scheme的数字塔时开始的...但我真的更感兴趣的是代表“Type1可以是Type2加x,y,......中的任何一个”的更一般的问题。

3 个答案:

答案 0 :(得分:0)

  

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

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

  

但是现在你必须确保将你的子包装为超级

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

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

然后,您将使用Sub但期望Super的任何上下文都会被捕获。我猜你已经知道了,你的意思是什么呢?

答案 1 :(得分:0)

你不能拥有像

这样的东西
data Sub = SubA | SubB
data Super = Sub | SuperB

假设允许使用上述语法,那么问题就是值构造函数SubA,您无法判断其类型是Sub还是Super。这就是你需要在构造函数中包装类型的原因。

对于你的第二个例子,你正在做的方式应该是默认的做法,但你可以做一个黑客来使它更容易,虽然我不建议这样做因为使用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)。

答案 2 :(得分:0)

您可能希望使用镜头(Control.Lens)库及其Data.Data和Data.Typleable实例。镜头是尝试在列表,元组和所有其他数据类型中解决这些类型的多级问题。

>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,那么它将是真的。但是,应该可以将此限制为仅限于您的用例。

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