Search code examples
haskelltypesalgebraic-data-types

multiple declaration errors of algebraic data type


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..


Solution

  • 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.