cs252r : Advanced Functional Programming - Fall 2006

These pages are a record of the in-class discussions for the graduate class "Advanced Functional Programming" given at Harvard University in the Fall of 2006.

December 4, 2006


Basic Questions

For these questions, consider the following datatype definition:

data Exp = Var Name
         | Lam Name Exp
         | App Exp Exp

Is the type Exp isomorphic to a sum of products? If so, exhibit a sum of products to which Exp is isomorphic, and write the isomorphism using the types in the paper. If not, explain why not.

fromExp :: Exp -> Plus Name (Plus (Pair Name Exp) (Pair Exp Exp))
fromExp e = case e of
  Var n     -> Inl n
  Lam n e   -> Inr $ Inl $ Pair n e
  App e1 e2 -> Inr $ Inr $ Pair e1 e2

What happens if you define a new type Exp' of kind (* -> *) by ``untying the recursive knot.'' Is the resulting type Exp' a isomorphic to a sum of products? Is the isomorphism any easier to deal with?

Exp' a is isomorphic if and only if a is isomorpihc.

The paper claims that "Haskell's construct for defining new types, the data declaration, introduces a type that is isomorphic to a sum of products." Using your answers to the first two question, and using the phrase ``recursion equation,'' can you sharpen this claim a little bit?

Is the type Name necessary, or do Unit, Plus, and Pair provide sufficient expressive power? Justify your answer.

Suppose you are designing a core language. What would you recommend adding to Unit, Plus, and Pair to provide sufficient expressive power for the translation of Haskell programs?

Is it a coincidence that the value structure of 2D is:

 v ::= () | (v,v) | Inl v | Inr v 

Abstract syntax trees with free and bound variables

In Ralf's paper, a tree is just a tree, and all trees can be formed from +, x, and (). But in an abstract-syntax tree, certain leaves are special: the variables. Moreover, variables in an abstract-syntax tree take one of two forms: a variable is either a free occurrence or a binding instance. And as we all know, a binding instance takes one or more subtrees as its scope.

Norman's Solution

module Gen where
import qualified List

data Unit                     =  Unit
data Plus a b                 =  Inl a | Inr b
data Pair a b                 =  Pair { outl :: a, outr:: b }
data Binder a                 =  Bind { bindingInstance :: Name, body :: a }
data Occurrence               =  Free { freeName :: Name }
data Isomorphism a b          =  Iso { fromData :: b -> a, toData :: a -> b }

type Name = Int
data Exp = Var Name
         | Lam Name Exp
         | App Exp Exp

exp :: (Generic g) => g Exp
exp = datatype (Iso fromExp toExp)

fromExp (Var n) = Inl (Free n)
fromExp (Lam n e) = Inr (Inl (Bind n e))
fromExp (App e e') = Inr (Inr (Pair e e'))

toExp (Inl (Free x)) = Var x
toExp (Inr (Inl (Bind n e))) = Lam n e
toExp (Inr (Inr (Pair e e'))) = App e e'

instance TypeRep Exp where
    typeRep = datatype (Iso fromExp toExp)

class Generic g where
  unit                        :: g Unit
  plus                        :: (TypeRep a, TypeRep b) => g (Plus a b)
  pair                        :: (TypeRep a, TypeRep b) => g (Pair a b)
  binder                      :: (TypeRep a) => g (Binder a)
  occurrence                  :: g (Occurrence)
  datatype                    :: (TypeRep a) => Isomorphism a b -> g b
  char                        :: g Char
  int                         :: g Int

class TypeRep a where
  typeRep                     :: (Generic g) => g a

instance TypeRep Unit where
  typeRep                     =  unit
instance (TypeRep a, TypeRep b) => TypeRep (Plus a b) where
  typeRep                     =  plus
instance (TypeRep a, TypeRep b) => TypeRep (Pair a b) where
  typeRep                     =  pair
instance TypeRep Char where
  typeRep                     =  char
instance TypeRep Int where
  typeRep                     =  int
instance (TypeRep a) => TypeRep (Binder a) where
  typeRep                     =  binder
instance TypeRep Occurrence where
  typeRep                     =  occurrence

newtype FreeVars a = FreeVars { appFreeVars :: a -> [Name] }

instance Generic FreeVars where
  unit = FreeVars (\_ -> [])
  plus = FreeVars (\x -> case x of { Inl l -> freeVars l ; Inr r -> freeVars r })
  pair = FreeVars (\x -> List.union (freeVars $ outl x) (freeVars $ outr x))
  binder = FreeVars (\x -> List.delete (bindingInstance x) (freeVars $ body x))
  occurrence = FreeVars (\x -> [freeName x])
  datatype iso = FreeVars (\x -> freeVars $ fromData iso x)
  char = FreeVars (\_ -> [])
  int  = FreeVars (\_ -> [])
         
freeVars :: (TypeRep a) => a -> [Name]
freeVars = appFreeVars typeRep

x = 1
y = 2
z = 3

f1 = freeVars (Lam x $ Lam y $ Var x) 
f2 = freeVars (Lam x $ Lam y $ Var y) 
f3 = freeVars (Lam x $ Lam y $ Var z) 
f4 = freeVars (App (Var x) $ App (Var y) (Var z))
f5 = freeVars $ Lam y $ (App (Var x) $ App (Var y) (Var z))

BibTeX

@InProceedings{Ralf-Hinze2004
  , isbn       = "1-58113-905-5"
  , author     = "Ralf Hinze"
  , year       = 2004
  , publisher  = "ACM Press"
  , title      = "Generics for the masses"
  , address    = "New York, NY, USA"
  , location   = "Snow Bird, UT, USA"
  , url        = "http://doi.acm.org/10.1145/1016850.1016882"
  , pages      = "236--243"
  , booktitle  = "ICFP '04: ACM SIGPLAN international conference on Functional programming"
  }
@InProceedings{Ralf-Hinze2000
  , title      = "A New Approach to Generic Functional Programming"
  , month      = "January"
  , url        = "http://www.informatik.uni-bonn.de/~ralf/publications"
  , author     = "Ralf Hinze"
  , year       = 2000
  , booktitle  = "ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages"
  }