Search code examples
haskellabstract-data-type

Nested/Sub data types in haskell


So what would be nice is if you could do something like the following (not necessarily with this format, just the general idea):

data Sub = SubA | SubB
data Super = Sub | SuperB

isSub :: Super -> Bool
isSub Sub = True
isSub _ = False

So isSub SubA would report True (instead of an error.) At the moment you might do something like:

data Super = SubA | SubB | SuperB

isSub :: Super -> Bool
isSub SubA = True
isSub SubB = True
isSub _ = False

It's not terrible or anything, but it doesn't expand nicely (as in if Sub when up to SubZ this would be terribly clunky) and it doesn't allow you to add the Sub types to their own type-class. To avoid that problem you can wrap Sub:

data Sub = SubA | SubB
data Super = SuperA Sub | SuperB

isSub :: Super -> Bool
isSub (SuperA _) = True
isSub _ = False

But now you have to make sure to wrap your Subs to use them as a Super... again not terrible; just doesn't really express the semantics I'd like very well (i.e. Super can be any Sub or SuperB). The first (legal) example is "Super can be SubA..." and the second is "Super can be SuperA that takes a Sub..."

EDTI: Change some names to avoid conflation with music stuff.

P.S. Technically, this started when I was thinking about how to represent Scheme's numeric tower in Haskell... but I'm really more interested in the more general issue of representing "Type1 can be any of Type2 plus x, y, ...)


Solution

  • It's not terrible or anything, but it doesn't expand nicely

    It would be fine if you used some Template Haskell. I'd look at the derive tool's makeIs routine for guidance.

    But now you have to make sure to wrap your Subs to use them as a Super

    No, the type system will tell you if you forgot. For example, if you have

    data Super = Sub Sub | Super
    data Sub = SubA | SubB
    

    Then any context in which you use a Sub but expect a Super will be caught. I'm guessing you already know that so did you mean something else?