Before I make the suggestion against using such types, let me explain some background.
Either
is a sum type, and a pair or 2-tuple is a product type. Sums and products can exist over arbitrarily many underlying types (sets). However, in Haskell, only tuples come in a variety of sizes out of the box. Either
on the other hand, can to be (arbitrarily) nested to achieve that: Either Foo (Either Bar Baz)
.
Of course it's easy to instead define e.g. the types Either3
and Either4
etc, in the spirit of 3-tuples, 4-tuples and so on.
data Either3 a b c = Left a | Middle b | Right c
data Either4 a b c d = LeftMost a | Left b | Right c | RightMost d
...if you really want. Or you can find a library the does this, but I doubt you could call it "standard" by any standards...
However, if you do define your own generic sum and product types, they will be completely isomorphic to any type that is structurally equivalent, regardless of where it is defined. This means that you can, with relative ease, nicely adapt your code to interface with any other code that uses an alternative definition.
Furthermore, it is even very likely to be beneficial because that way you can give more meaningful, descriptive names to your sum and product types, instead of going with the generic tuple and either. In fact, some people advise for using custom types because it essentially adds static type safety. This also applies to non-sum/product types, e.g.:
employment :: Bool -- so which one is unemplyed and which one is employed?
data Empl = Employed | Unemployed
employment' :: Empl -- no ambiguity
or
person :: (Name, Age) -- yeah but when you see ("Erik", 29), is it just some random pair of name and age, or does it represent a person?
data Person = Person { name :: Name, age :: Age }
person' :: Person -- no ambiguity
— above, Person
really encodes a product type, but with more meaning attached to it. You can also do newtype Person = Person (Name, Age)
, and it's actually quite equivalent anyway. So I always just prefer a nice and intention-revealing custom type. The same goes about Either
and custom sum types.
So basically, Haskell gives you all the tools necessary to quickly build your own custom types with very clean and readable syntax, so it's best if we use it not resort to primitive types like tuples and either. However, it's nice to know about this isomorphism, for example in the context of generic programming. If you want to know more about that, you can google up "scrap your boilerplate" and "template your boilerplate" and just "(datatype) generic programming".
P.S. The reason they are called sum and product types respectively is that they correspond to set-union (sum) and set-product. Therefore, the number of values (or unique instances if you will) in the set that is described by the product type (a, b)
is the product of the number of values in a
and the number of values in b
. For example (Bool, Bool)
has exactly 2*2 values: (True, True)
, (False, False)
, (True, False)
, (False, True)
.
However Either Bool Bool
has 2+2 values, Left True
, Left False
, Right True
, Right False
. So it happens to be the same number but that's obviously not the case in general.
But of course this can also be said about our custom Person
product type, so again, there is little reason to use Either
and tuples.