In this post I want to talk a bit about my favorite general-purpose
functional programming language, Twelf. If that sentence gives you
cognitive dissonance, please read on!

Really, what I am going to be describing is a very shallow
embedding of a pure functional language within Twelf. For
familiarity (though at a cost of expressiveness), I will limit our language to an ML-like, call-by-value
fragment (with arbitrary recursive datatypes and recursive
functions), rather than a fully polarized type theory. For fun, our
language will also include Haskell-style typeclasses. Our two weapons will be
traditional LF-style (dependently-typed) higher-order abstract syntax, and the
defunctionalization trick I described
a year ago. Don't worry, we won't be proving any theorems, only writing programs.

(Note: there is nothing scary about delimited continuations—think of them as pure ML functions, or entailments, or morphisms in a category.) Expressions in our language are constructed out of values and continuations, as follows:

Because we are really restricting to types of positive
polarity, values are built by applying constructors, while
continuations are defined by pattern-matching on values. The
latter principle is expressed (in defunctionalized form) by the apply function, a Twelf logic program:

apply : kon A B -> val A -> exp B -> type.
%mode apply +K +V -E.

Now, without knowing anything else about values and continuations,
we can already give our language a generic (big-step) operational
semantics:

Just as we do in Haskell, we can define continuations (functions)
by giving them a type declaration, and then a list of
pattern-matching clauses. For example, here we define the
boolean operations "and" and "or":

Okay, hopefully by now you are convinced that in this style we we can
write more or less ordinary (effect-free) ML programs. Next we turn
to typeclasses. Typeclasses are basically type-indexed (or type
constructor-indexed) records, and so their encoding in Twelf follows
the same pattern of defunctionalization (i.e., for the
polarity-sensitive, because they are negative values).
Here we introduce a few typeclasses familiar from Haskell: