简体   繁体   English

在Haskell中使用数据类型

[英]Using data types in Haskell

I have started this a new question as it became a follow-on from my previous question. 我已经开始这是一个新问题,因为它成为我上一个问题的后续问题。

If I have two data types which are composed of similar constructors: 如果我有两个由类似构造函数组成的数据类型:

data A = X | Y | Z
data B = X | Y

is there no way I can somehow represent this as: 是不是我不能以某种方式表示这个:

data A = C | Z
data B = C

data C = X | Y

if you can see what I am doing- I am trying to group the X | 如果你能看到我在做什么 - 我正在尝试将X |分组 Y into one data type, which can then be used by multiple other data types. Y为一种数据类型,然后可由多种其他数据类型使用。 I cannot seem to get the compiler to allow this, or if it does, I cannot pattern-match against the X or Y, only the C?? 我似乎无法让编译器允许这个,或者如果它,我不能模式匹配X或Y,只有C ??

I get the error message that C has been declared multiple times. 我收到多次声明C的错误消息。

I thought I could maybe use types, but they do not allow multiple typings. 我以为我可以使用类型,但它们不允许多种类型。

EDIT 编辑

Even if I declare the long way (like below), it still won't compile and says X and Y have multiple declarations: 即使我声明了很长的路(如下所示),它仍然无法编译,并且说X和Y有多个声明:

data A = X | Y | Z
data B = X | Y

Not only can't you do this, you also can't do your first option - ie you can't have two types in the same module that both have constructors named X and Y . 你不仅不能这样做,你也不能做你的第一个选择 - 即你不能在同一模块中有两种类型,它们都有名为XY构造函数。

If you could do this, what should the type of X be - C , A or B ? 如果你能做到这一点, X的类型应该是什么 - CAB The most obvious answer would be C , but then you wouldn't be able to use it in a context where an A or a B are required (note that Haskell has no subtyping), so that would defeat the purpose of the whole construct. 最明显的答案是C ,但是你不能在需要AB的上下文中使用它(注意Haskell没有子类型),这样就会破坏整个构造的目的。

The best you can do is to wrap C in a constructor of A and B, ie: 你能做的最好的事情是将C包装在A和B的构造函数中,即:

data A = AC C | Z
data B = BC C
data C = X | Y

Then you could wrap a C with either the AC or the BC constructor to create a value of type A or B respectively. 然后,您可以使用ACBC构造函数包装C,以分别创建类型AB的值。

The reason you can't do this 你不能这样做的原因

data A = X | Y | Z
data B = X | Y

is as follows. 如下。 Say you write some code later on: 假设你稍后写了一些代码:

foo n = (n,X)

which builds a pair consisting of n in the first slot and X in the second slot. 它构建了一对由第一个槽中的n和第二个槽中的X组成的对。 What type should the compiler infer? 编译器应该推断出什么类型? A valid type would be 有效的类型是

foo :: a -> A -> (a,A)

since X is a constructor of type A , but equally valid is 因为XA类型的构造函数,但同样有效

foo :: a -> B -> (a,B)

since X is a constructor of type B . 因为XB类的构造函数。 If you have two constructors with the same name, you can't infer a unique type for functions that use them. 如果有两个具有相同名称的构造函数,则无法推断使用它们的函数的唯一类型。 So you are disallowed from giving two constructors in the same module the same name. 因此,您不允许在同一模块中为两个构造函数提供相同的名称。

You can't do this: 你不能这样做:

data A = C | Z
data B = C

data C = X | Y

(As an aside, if B is identical to C , then why have B at all?) (顺便说一句,如果B C 相同 ,那么为什么要有B ?)

But what you can do is something like this: 但你可以做的是这样的事情:

data A = A_Other C | Z
data B = B_Other C

data C = X | Y

Then you can pattern match like this: 然后你可以像这样模式匹配:

foo :: A -> String
foo (A_Other X) = "X"
foo (A_Other Y) = "Y"
foo (        Z) = "Z"

bar :: B -> String
bar (B_Other X) = "X"
bar (B_Other Y) = "Y"

foobar :: C -> String
foobar X = "X"
foobar Y = "Y"

If that makes sense... 如果这是有道理的......

You cannot do what you want because you are declaring multiple data constructors. 你不能做你想要的,因为你声明了多个数据构造函数。 In

data A = X | Y | Z

You are actually introducing the type A which has 3 constructors (values) X , Y , and Z . 实际上,您正在引入具有3个构造函数(值) XYZ的类型A This is why your first piece of code won't compile, it sees the same name listed as constructors for two different types! 这就是为什么你的第一段代码不能编译,它会看到同样的名称被列为两种不同类型的构造函数! If you could do this you'd have to ask yourself is 如果你能做到这一点,你必须问自己是

X :: A

or 要么

X :: B

which in a non object-oriented context is scary! 在非面向对象的环境中,这是可怕的! So you need to provide different constructor names to share that underlying data, C . 因此,您需要提供不同的构造函数名称来共享底层数据C

If you want to factor this, you can do as the other posts have suggested and factored-out data in unique constructors for each datatype 如果你想要考虑这一点,你可以这样做,因为其他帖子在每个数据类型的唯一构造函数中都有建议和分解数据

data A = CForA C | Z
data B = CForB C

data C = X | Y

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

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