Data type with type constraint in Wadler - Essence of functional programming paper,

129 views Asked by At

In Phil Wadler's paper : The essence of functional programming, Wadler describes the application of Monads using a simple interpreter program. The program is as shown below:

A term is either a variable, a constant, a sum, a lambda expression, or an application. The following will serve as test data.

term0 = (App (Lam "x" (Add (Var "x") (Var "x"))) (Add (Con 10) (Con 11)))

For our purposes, a monad is a triple (M,unitM,bindM) consisting of a type constructor M and a pair of polymorphic functions.

unitM :: a -> M a
bindM :: M a -> (a -> M b) -> M b

Then the interpreter program is described as:

type Name = String

data Value = Wrong
           | Num Int
           | Fun (Value -> M Value)

I do not see how M Value has been included here. My understanding that Haskell does not allow type constraints on data type constructors?

Further details: The complete program is below:

type Name = String
data Term = Var Name
          | Con Int
          | Add Term Term
          | Lam Name Term
          | App Term Term
data Value = Wrong
           | Num Int
           | Fun (Value -> M Value)
type Environment = [(Name, Value)]
interp :: Term -> Environment -> M Value
interp (Var x) e = lookup x e
interp (Con i) e = unitM (Num i)
interp (Add u v) e = interp u e `bindM` (\a ->
                                            interp v e `bindM` (\b ->
                                                                  add a b))
interp (Lam x v) e = unitM (Fun (\a -> interp v ((x,a):e)))
interp (App t u) e = interp t e `bindM` (\f ->
                                             interp u e `bindM` (\a ->
                                                                     apply f a))

lookup :: Name -> Environment -> M Value
lookup x [] = unitM Wrong
lookup x ((y,b):e) = if x==y then unitM b else lookup x e

add :: Value -> Value -> M Value
add (Num i) (Num j) = unitM (Num (i+j))
add a b = unitM Wrong

apply :: Value -> Value -> M Value
apply (Fun k) a = k a
apply f a = unitM Wrong

As can be seen interp (Lam x v) e = unitM (Fun (\a -> interp v ((x,a):e))) requires definition data Value = ... | Func (Value -> M Value)

I tried to implement interp (Lam x v) by using data Value = ... | Func (Value -> Value), but it did not seem possible to me.

1

There are 1 answers

3
Jonas Duregård On

M is not a constraint, it is a type constructor. So writing M Value is similar [Value], Maybe Value etc. A constraint would be something like Monad m => m Value, where m is a type variable, not a type constructor and Monad m is the constraint (Monad is a type class).

In the paper, the definition of the type M value has not been presented, and it is later shown that you can give it different definitions (the definitions would involve defining data M v = ... and the functions bindM and unitM).

Edit: If you wanted to have a constraint, you would change the definition of value like this:

data Value m = Wrong
             | Num Int
             | Fun (Value m -> m (Value m))

And then have the constraint in the types of functions, e.g.:

interp :: Monad m => Term -> Environment -> m (Value m)