We now translate the above example from Java to Haskell and arrive at essentially the finally tagless approach.

This approach has been introduced in the paper “Finally Tagless, Partially Evaluated”. It enjoys many interesting properties, but we are only going to focus on how it helps us to solve the expression problem.

First, we consider how expressions are represented in the finally tagless approach.

The Haskell counterpart of the interface ExpAlg<T> in Java is a typeclass ExpAlg :

class ExpAlg t where lit :: Int -> t add :: t -> t -> t

The expression (1 + (2 + 3)) is represented as follows:

e1 = add (lit 1) (add (lit 2) (lit 3))

and its inferred type ExpAlg t => t can be read as a statement that the term e1 can be given any type t as long as t is an instance of the typeclass ExpAlg , i.e., supports the operations lit and add .

What is remarkable is that at the stage of desugaring the typeclass ExpAlg is translated into a record type with fields lit and add , instance declarations of ExpAlg are translated into record values of this type, and the expression e1 is translated into a function taking as an argument a record value corresponding to an instance declaration of ExpAlg for a given type t . This record value is a direct analog of the concrete factory f in Java.

The difference between Haskell and Java is that in Haskell for every pair of a typeclass and a type there can be at most one instance declaration, and once this instance declaration is defined, it remains implicitly in the scope and is passed around automatically by the compiler. In Java, there can be many implementations of a given generic interface instantiated with a given type, and these implementation are entities in the program that have names and have to be passed around explicitly.

To understand how operations are defined in the finally tagless approach, let us look again at evaluation of expressions. We are going to simplify the Java implementation first to make translation to Haskell more obvious.

Namely, we observe that we don’t have to make Eval an interface, although conceptually this is cleaner. After all, if all we know about an object is that it implements the interface Eval , then all we can do with this object is to call the method eval . Therefore, for an external observer such an object is practically indistinguishable from an object of a class Eval with a public field eval of type int . With this change, the definition of the factory EvalExp becomes:

class Eval { public int eval ; } class EvalExp implements ExpAlg <Eval> { Eval lit ( int n ) { return Eval(n); } Eval add ( Eval x , Eval y ) { return Eval(x.eval + y.eval); } }

To evaluate the expression e1 we pass it an instance of the class EvalExp , which produces an object of the class Eval , which we can ask the value of its field eval :

int v1 = e1( new EvalExp ()).eval;

The class Eval is a wrapper around the type int . In Haskell, we introduce a wrapper Eval around the type Int implemented, say, as a newtype :

newtype Eval = Eval { eval :: Int }

The definition of the class EvalExp translates into an instance declaration of the typeclass ExpAlg for the type Eval :

instance ExpAlg Eval where lit n = Eval n add x y = Eval $ eval x + eval y

To evaluate the expression e1 we restrict its type ExpAlg t => t to Eval , which is similar to applying the expression e1 to the concrete factory EvalExp in Java, and then the obtained value of type Eval can be queried the value of the field eval :

v1 = eval (e1 :: Eval )

In fact, we don’t have to explicitly restrict the type of e1 to Eval as the compiler will infer this automatically from the fact that e1 is passed as an argument to the function eval :: Eval -> Int .

In Java, extension of the language with the multiplication operation corresponded to extension of the interface ExpAlg<T> to MulAlg<T> with the method mul . In Haskell, this translates into a definition of a new typeclass MulAlg that is a subclass of ExpAlg :

class ExpAlg t => MulAlg t where mul :: t -> t -> t

Expressions containing multiplication will now have the type MulAlg t => t , for example:

e2 = mul (lit 4) (add (lit 5) (lit 6))

To extend the definition of the operation eval , we perform the same transformation as above: we replace the interface Eval with a class Eval with a public field of type int . Then the definition of the class EvalMul implementing the interface MulAlg<Eval> translates in Haskell into a definition of an instance declaration of the typeclass MulAlg for the type Eval :

instance MulAlg Eval where mul x y = Eval $ eval x * eval y

Finally, we consider an example of adding new operations in the finally tagless approach. Let us implement conversion to string.

We transform the object algebras implementation of conversion in Java similarly to what we did to the implementation of evaluation: we replace the interface View with a class View with a public field view of the type String . Then in Haskell this all is going to turn into an instance declaration of the typeclass ExpAlg for a type View that is a newtype wrapper around String :

newtype View = View { view :: String } instance ExpAlg View where lit n = View $ show n add x y = View $ "(" ++ view x ++ " + " ++ view y ++ ")"

Extension of the operation view to expressions containing multiplication is done similarly and amounts to defining an instance declaration of the typeclass MulAlg for the type View :

instance MulAlg View where mul x y = View $ "(" ++ view x ++ " * " ++ view y ++ ")"

The encoding we have arrived at is almost identical to that proposed in “Finally Tagless, Partially Evaluated”. The difference is that in Haskell there is no need to make MulAlg a subclass of ExpAlg : we can define it as a separate typeclass:

class MulAlg t where mul :: t -> t -> t