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 | Y into one data type, which can then be used by multiple other data types. 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??
I get the error message that C has been declared multiple times.
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:
data A = X | Y | Z
data B = X | Y
Not only can't you do this, you also can't do your first option - i.e. you can't have two types in the same module that both have constructors named X
and Y
.
If you could do this, what should the type of X
be - C
, A
or B
? 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.
The best you can do is to wrap C in a constructor of A and B, i.e.:
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.
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. 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
foo :: a -> B -> (a,B)
since X
is a constructor of type B
. 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?)
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...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With