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
- Generics for the masses. Ralf Hinze.
- A New Approach to Generic Functional Programming. Ralf Hinze.
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"
}