data A=A
data B=B
data AB=A|B
Which makes a sum type AB from A and B.
but the last line induces a compile error \"multiple declarations of
Sum types have to be tagged. a+a
has to have two injections from a
.
To understand how algebraic data types work, take a simple example:
data X = A | B C
This defines a new type constructor, X
, along with data constructors A
and B
. The B
constructor takes/holds an argument of type C.
The primary canonical sum type in Haskell is Either
:
data Either a b = Left a | Right b
Because the type of the value created using data constructor A
or B
will be ambiguous. When I have a = B
for instance, what is the type of a
? It is A
or AB
?
You should consider using different data constructor as follows:
data A = MkA
data B = MkB
data AB = A A | B B
When you say data AB = A | B
, you are not referring to the types A
and B
, but rather are defining data constructors A
and B
. These conflict with the constructors defined on the the previous lines.
If you want to create a type AB
that is the sum of A
and B
, you must provide data constructors that wrap the types A
and B
, e.g.:
data AB = ABA A | ABB B
You're getting fooled. You think when you write data A=Int|Bool
that you are saying that a value of type A
can be a value of type Int
or a value of type Bool
; but what you are actually saying is that there are two new value-level constructors named Int
and Bool
, each containing no information at all, of type A
. Similarly, you think that data AB=A|B
says you can either be of type A
or type B
, but in fact you are saying you can either have value A
or value B
.
The key thing to keep in mind is that there are two namespaces, type-level and term-level, and that they are distinct.
Here is a simple example of how to do it right:
data A=A
data B=B
data AB=L A|R B
The last line declares two new term-level constructors, L
and R
. The L
constructor carries a value of type A
, while the R
constructor carries a value of type B
.
You might also like the Either
type, defined as follows:
data Either a b = Left a | Right b
You could use this to implement your AB
if you wanted:
type AB = Either A B
Similarly, you could use Either Int Bool
for your tagged union of Int
and Bool
.