Home > OS >  Haskell: Combining Maybe and Either types to a single type
Haskell: Combining Maybe and Either types to a single type

Time:08-05

I have to combined Maybe and Either into MayEither, with three constructors for Left, Right and Nothing called MyLeft, MyRight and MyNothing.

This is what I did:

data MayEither = Maybe  { myNothing :: Nothing }
               | Either { myLeft :: Left }
               | Either { myRight :: Right } deriving Show

But this gives me a Multiple declarations of ‘Either’ error. How can I properly combine the types?

CodePudding user response:

Two things need to happen:

  1. You need to give distinct names for each of your data constructors.
  2. You need to give the types of the fields in your records.

Note that Nothing, Left, and Right are data constructors for the Maybe and Either types -- they are not themselves types! So claiming that a field has type Nothing isn't quite right. Similarly, Maybe and Either are type constructors, so naming your data constructors after them is at best misleading, and in this case almost certainly simply wrong.

So let's try again. First we'll pick new data constructor names.

data MyEither = MyNothing { myNothing :: <TODO> }
              | MyLeft { myLeft :: <TODO> }
              | MyRight { myRight :: <TODO> }

Now, what type should myNothing have? Well, the whole point of Nothing/MyNothing is that there's, well, nothing there. So we shouldn't have that field at all!

data MyEither = MyNothing
              | MyLeft { myLeft :: <TODO> }
              | MyRight { myRight :: <TODO> }

What type should the myLeft field have? Well, presumably we'd like to be able to have anything in there. The way to allow that is to parameterize our type -- just like Maybe takes one type-level argument and Either takes two type-level arguments. We'll do what Either does, and take two arguments, so that our myLeft and myRight fields can be arbitrary and need not match.

data MyEither a b = MyNothing
                  | MyLeft { myLeft :: a }
                  | MyRight { myRight :: b }

This is now valid Haskell. BUT combining record syntax and sum types is almost always a bad idea. I think I would drop the field names entirely, if I were doing this myself.

data MyEither a b = MyNothing
                  | MyLeft a
                  | MyRight b
-- OR
data MyEither a b = MyNothing | MyLeft a | MyRight b
  • Related