///|
pub type Var String derive(Eq, Hash, Compare)

///|
type Subst @immut/hashmap.T[Var, Value] derive(Eq)

///|
pub struct CtorName {
  name : String
  arity : Int
} derive(Eq, Hash)

///|
impl Show for CtorName with to_string(self) {
  self.name
}

///|
impl Show for CtorName with output(self, logger) {
  logger.write_string(self.name)
}

///|
enum Pattern {
  PVar(Var)
  PCtor(CtorName, Array[Pattern])
  PAnd(Pattern, Pattern)
  POr(Pattern, Pattern)
  PNot(Pattern)
  PTop
  PBottom
} derive(Eq, Hash)

///|
enum Value {
  VApp(CtorName, Array[Value])
} derive(Eq, Show)

///|
struct Clause {
  pattern : Pattern
  expr : Expression
} derive(Eq)

///|
enum Expression {
  Default
  Var(Var)
  Ctor(CtorName, Array[Expression])
  Case(Expression, clauses~ : Array[Clause], default~ : Expression)
} derive(Eq)

///|
pub type! Match

///|
pub type! Step