Search code examples
haskellalgebraic-data-types

Haskell nested algebraic data type


I'm trying to model the following simple Scala ADT in Haskell:

sealed trait Value

sealed trait Literal < Value
case object Null extends Literal
case class IntLiteral(value: Int) extends Literal

case class Variable(name: String) < Value

I model the Literal trait:

Prelude> data Literal = Null | IntLiteral Int deriving (Show, Eq)

So far so good:

Prelude> Null
Null
Prelude> Null == IntLiteral 3
False
Prelude> IntLiteral 3 == IntLiteral 3
True

Now I try to introduce Variable:

data Value = Literal | Variable String deriving (Show, Eq)

Why doesn't this work?

Prelude> Null == Variable "foo"

<interactive>:3:9: error:
    • Couldn't match expected type ‘Literal’ with actual type ‘Value’
    • In the second argument of ‘(==)’, namely ‘Variable "foo"’
      In the expression: Null == Variable "foo"
      In an equation for ‘it’: it = Null == Variable "foo"

Solution

  • Null is of type Literal, Variable "foo" is of type Value. There can also be a data constructor Literal, unrelated to the type with the same name. These are just different things, living in separate namespaces, in Haskell. If you write

    data Value = Literal Literal | ...
    

    then, the first Literal is a name of a data constructor (creates values of type Value, in that case), the second is a name of a type.