multiple declaration errors of algebraic data type

2019-09-08 08:07发布

some algebraic data types..

data Cell0=Cell0 {c0str::Text,c0uid::Uid}
           deriving (Data,Typeable,Show)
data Cell1=Cell1 {c1start::Uid,c1end::Uid,c1str::Text,c1uid::Int}
           deriving (Data,Typeable,Show)
data Cell2=Cell2 {c2start::Uid,c2end::Uid,c2str::Text,c2uid::Int}
           deriving (Data,Typeable,Show)
data Acell=Cell0|Cell1

but the last line induces a compile error "multiple declarations of Cell0"

I also tried sth like this:

data A=Aasdfdsf {sdf::Text}
      deriving (Data,Typeable,Show)
data B=Bsdfsd
data AB=A|B

It compiles! so weired..

2条回答
倾城 Initia
2楼-- · 2019-09-08 08:23
data Acell=Cell0|Cell1

That's not how ADTs work.

What you're thinking when you write that seems to be "an Acell is either a Cell0 or a Cell1". But the Haskell spec says that this actually means "introduce a new type Acell, and introduce a new constructor Cell0 that takes no arguments, and introduce a new constructor Cell1 that takes no arguments".

Thus your type definition contains no references at all to the type Cell0, but it introduces a new constructor Cell0 that clashes with the existing constructor named Cell0. Hence the error.

Your second example with data AB=A|B does not work. It compiles, but if you'd tried it you'd see that you cannot put an element of the type A in the type AB. An AB is either the constructor A (containing no other data), or the constructor B (containing no other data); totally unrelated to the types A and B.

The problem is that ADTs have tagged unions; in every branch of a data declaration (separated by |) there must be a new constructor and then the types that will be stored in the constructor. So, for example, you could say:

data Acell = Acell0 Cell0 | Acell1 Cell1

The constructors function as "tags" and allow you to tell which "branch" is being used without looking at the data inside, and even if the branches actually store the same data (e.g. data Foo = L Integer | R Integer). There's no way to have untagged unions and leave out the constructors.

查看更多
聊天终结者
3楼-- · 2019-09-08 08:23

In the first example, you are in fact declaring the constructor Cell0 twice; once in the first type, and once in the last. You're doing the same for Cell1 aswell, but the compiler hasn't gotten there to produce an error. It doesn't matter that the constructors are of a different type; all constructors must have unique names (the same goes for record fields; an unfortunate part of Haskell).

In your second example, you never try to redeclare a constructor, so it compiles.

查看更多
登录 后发表回答