CS5205 Interpreters 1
CS5205: Foundations in Programming Languages
Interpreters.
CS5205 Interpreters 2
InterpretersInterpreters
• Compilers generate low-level code for execution
• Interpreters operate over abstract syntax of programs and would change the machine environment according to the commands of the programs.
• Advantage of Interpreters• more compact• easier to extend/modify• easier to debug• good for implementing small languages
• Disadvantage : overheads of interpretation
CS5205 Interpreters 3
TopicsTopics
• Monadic Interpreter• Error messages with positions• States• Output• Non-determinism
• Call-by-Value vs Call by Name• CPS vs Monads
Reference : The essence of functional programming. Phil Wadler invited talk at POPL 1992
CS5205 Interpreters 4
Simple LanguageSimple Language
• Abstract syntax tree
• Lambda calculus plus integer and addition
data Term = Var Name| Con Int| Add Term Term| Lam Name Term| App Term Term
type Name = String
CS5205 Interpreters 5
Simple InterpreterSimple Interpreter
• Value of Language
data Value = Wrong| Num Int| Fun (Value -> Value)
• Environment
• Interpreter
type Env = [(Name,Value)]
interp :: Term -> Env -> Value
Term
Env
Valueinterp
CS5205 Interpreters 6
Direct-Style Interpreter Direct-Style Interpreter
• Looking up environment
lookup :: Name -> Environment -> Valuelookup x [] = Wronglookup x ((y,b):r) = if x==y then b
else lookup x r
• Displaying a given value
instance Show Value where show Wrong = "<wrong>" show (Num i) = show i show (Fun f) = "<function>"
CS5205 Interpreters 7
Direct-Style Interpreter Direct-Style Interpreter
• Main interpreter
interp :: Term -> Environment -> Valueinterp (Var x) e = lookup x einterp (Con i) e = (Num i)interp (Add u v) e = let a = interp u e
b = interp v e in (add a b)
interp (Lam x v) e = (Fun (\a -> interp v ((x,a):e)))
interp (App u v) e = let f = interp u e b = interp v e in (apply f b)
CS5205 Interpreters 8
Direct-Style Interpreter Direct-Style Interpreter
• Adding two numbers
add :: Value -> Value -> Valueadd (Num i) (Num j) = (Num (i+j))add _ _ = Wrong
• Applying a function to its argument
apply :: Value -> Value -> Valueapply (Fun k) a = k aapply _ _ = Wrong
CS5205 Interpreters 9
Some Challenges Some Challenges
• Direct-style interpreter easier to write. However, it may be difficult to add new features. Example:
• What if we wish to add more meaningful error messages?
• What if we wish to count the number of operations that are performed by the interpreter?
• What if we wish to implement call-by-name interpretation?
CS5205 Interpreters 10
Monoids vs Monads Monoids vs Monads
• Recall that monoid M is a triple:
( M, i :: M,
:o :: M -> M -> M )
• that satisfies three laws:
i :o x = xx :o i = x
x :o (y :o z) = (x :o y) :o z
CS5205 Interpreters 11
Monoids vs Monads Monoids vs Monads
• Similarly, monad M is a more complex triple:
( M, return :: a -> M a,
>>= :: M a -> (a -> M b) -> M b )
• that satisfy three laws:
(return a) >>= k = k am >>= return = mm >>= (\a -> (k a) >>= (\b -> h b)) = (m >>= (\a -> k a)) >>= (\b -> h b)
CS5205 Interpreters 12
Monadic Interpreter Monadic Interpreter
• We can implement our interpreter using monadic style.
interp :: Term -> Environment -> M Value
interp (Var x) e = lookup x einterp (Con i) e = return (Num i)interp (Add u v) e = do a <- interp u e
b <- interp v e (add a b)
interp (Lam x v) e = return (Fun (\a -> interp v ((x,a):e)))
interp (App u v) e = do f <- interp u e b <- interp v e (apply f b)
CS5205 Interpreters 13
Monadic Interpreter Monadic Interpreter
• Looking up environment
lookup :: Name -> Environment -> M Valuelookup x [] = return Wronglookup x ((y,b):r) = if x==y then return b
else lookup x r
• Modified value type
data Value = Wrong | Num Int | Fun (Value -> M Value)
CS5205 Interpreters 14
Monadic Interpreter Monadic Interpreter
• Adding two numbers
add :: Value -> Value -> M Valueadd (Num i) (Num j) = return (Num (i+j))add _ _ = return Wrong
• Applying a function to its argument
apply :: Value -> Value -> M Valueapply (Fun k) a = k aapply _ _ = return Wrong
CS5205 Interpreters 15
Monadic Interpreter Monadic Interpreter
• Identity Monad
type M t = t
instance Monad M where return a = a m >>= k = (k m)
data M t = Id t
instance Monad M where return a = Id a (Id m) >>= k = (k m)
• Using an isomorphic data declaration :
CS5205 Interpreters 16
Adding Error MessageAdding Error Message
• To provide more meaningful error messages, we can use a new monad.
data E t = Success t | Error Stringtype M t = E t
instance Monad M where return a = Success a (Success v) >>= k = k v (Error s) >>= k = (Error s)
errorM :: String -> M t errorM s = Error s
CS5205 Interpreters 17
Change Wrong to Error MessagesChange Wrong to Error Messages
• Adding two numbers
add :: Value -> Value -> M Valueadd (Num i) (Num j) = return (Num (i+j))add a b = errorM “Adding “++ show i++show j ++ “:should be numbers!”
• Applying a function to its argument
apply :: Value -> Value -> M Valueapply (Fun k) a = k aapply f _ = errorM “Argument “
++show f++” must be a function”
CS5205 Interpreters 18
• Looking up environment
lookup :: Name -> Environment -> M Valuelookup x [] = errorM “Unknown Var”
++ show xlookup x ((y,b):r) = if x==y then return b
else lookup x r
• Modified value type
data Value = Num Int | Fun (Value -> M Value)
Change Wrong to Error MessagesChange Wrong to Error Messages
CS5205 Interpreters 19
Adding Error Message with PositionAdding Error Message with Position
• To provide more meaningful error messages, we can use a new monad.
data E t = Success t | Error Stringtype M t = Position -> E ttype Position = Int
instance Monad M where return a= (\p -> return a) m >>= k = (\p -> (m p) >>=
(\x -> k x p))
errorM :: String -> M t errorM s = \ p -> Error ("Line "++show p
++ ": “++ s))
CS5205 Interpreters 20
Language with PositionLanguage with Position
• Abstract syntax treedata Term = Var Name
| Con Int| Add Term Term| Lam Name Term| App Term Term| At Position Term
• Key changes to Interpreter
interp :: Term -> Environment -> M Valueinterp (At p t) e = resetP p (interp t e)
resetP :: Position -> M a -> M aresetP q m = (\p -> (m q))
CS5205 Interpreters 21
Interpreter with StatesInterpreter with States
• Assume we wish to keep track of the number of additions and applications performed by a given interpreter.
• Requires a state monad, captured by :
type M t = State -> (State,t)type State = Int
instance Monad M where return a = (\s -> (s,a)) m >>= k = (\s -> let (s1,v1) = m s
in k v1 s1)
CS5205 Interpreters 22
Interpreter with StatesInterpreter with States
• Read state by:
getState :: M StategetState = \s -> (s,s)
• Update state by:
tickS :: M ()tickS = \s -> (s+1,())
clearS :: M ()clearS = \s -> (0,())
CS5205 Interpreters 23
Changes to the State InterpreterChanges to the State Interpreter
interp :: Term -> Environment -> M Value
interp (Add u v) e = do a <- interp u e b <- interp v e tickS add a b)
interp (App u v) e = do f <- interp u e b <- interp v e
tickS (apply f b)
CS5205 Interpreters 24
TopicsTopics
• Monadic Interpreter• Error messages with positions• States• Output• Non-determinism
• Call-by-Value vs Call by Name• CPS vs Monads
CS5205 Interpreters 25
Interpreter with OutputInterpreter with Output
• May like commands to write output to terminal
• Solution :
type M t = (String, t)
instance Monad M where return a= (“”,a) m >>= k = let (r, a)=m
(s, b)=k a in (r++s, b)
instance Show (M t) where show (s,a) = “Output : “++s++
” Value: “++show a
CS5205 Interpreters 26
Language with OutputLanguage with Output
• Abstract syntax treedata Term = Var Name
| …| Out Term
• Key changes to Interpreter
interp :: Term -> Environment -> M Valueinterp (Out t) e = do v <- (interp t e)
outM v return v
outM :: Value -> M ()outM v = (show v++” ;”, ())
CS5205 Interpreters 27
Non-Deterministic LanguageNon-Deterministic Language
• We may have a non-determinstic operatordata Term = Var Name
| …| Fail| Amb Term Term
• An example
Add (Con 3) (Amb (Con 1) (Con 2))
This adds 3 to a choice of either 1 or 2, giving either 4 or 5 as its set of possible outcomes.
CS5205 Interpreters 28
Non-Deterministic MonadNon-Deterministic Monad
• Solution :
type M t = [t]
instance Monad M where
return a = [a] m >>= k = [b | a <- m, b <- k a]
zeroM = [] plusM m k = m ++ k
CS5205 Interpreters 29
Changes to InterpreterChanges to Interpreter
• Key changes to Interpreter
interp :: Term -> Environment -> M Value
interp Fail e = zeroM
interp (Amb a b) e = interp a e `plusM`interp b e
CS5205 Interpreters 30
TopicsTopics
• Monadic Interpreter• Error messages with positions• States• Output• Non-determinism
• Call-by-Value vs Call by Name• CPS vs Monads
CS5205 Interpreters 31
Call-by-Name InterpreterCall-by-Name Interpreter
• Existing interpreter is call-by-value since the argument is evaluated before entering the function body.
interp (Lam x v) e = return (Fun (\a -> interp v ((x,a):e)))
interp (App u v) e = do f <- interp u e b <- interp v e (apply f b)
interp (App u v) e = do f <- interp u e (apply f (interp v e) )
type Environment = [(Name, M Value)]data Value = … | Fun (M Value -> M Value)
• To make into call-by-name interpreter, change :
CS5205 Interpreters 32
Call-by-Name InterpreterCall-by-Name Interpreter
• Call-by-name interpretation terminates more often .
• An example is:
t = (Lam “x” (App (Var “x”) (Var “x”)))
loop = App t t
constfn = Lam “x” (Con 13)
expr = App constfn loop
CS5205 Interpreters 33
Continuation-Passing Style (CPS)Continuation-Passing Style (CPS)
• CPS style requires each function to carry a ‘continuation’ which must be applied to the result of the function. Each continuation is like a goto method.
• In CPS style, the addition method would be:
add :: Int -> Int -> (Int -> Cont) -> Contadd x y c = c (x+y)
• Doubling a number would be:
double :: Int -> (Int -> Cont) -> Contdouble x c = add x x c
sub,mult :: Int -> Int -> (Int -> Cont) -> Conteq :: Int -> Int -> (Bool -> Cont) -> Cont
CS5205 Interpreters 34
Continuation-Passing Style (CPS)Continuation-Passing Style (CPS)• How about CPS-style for factorial.
fact :: Int -> (Int -> Cont) -> Contfact n c = if n==0 then c 1
else fact (n-1) (\ r -> c (n*r))
• More religiously:
fact :: Int -> (Int -> Cont) -> Contfact n c = eq n 0 (\b -> if b then c 1
else sub n 1 (\m -> fact m (\ r ->
mult n r c)))
CS5205 Interpreters 35
Continuation-Passing Style (CPS)Continuation-Passing Style (CPS)
• Advantages:
• tail-recursive code• better modularity for easier code changes
• Disadvantage
• harder to read (higher-order)
CS5205 Interpreters 36
CPS MonadCPS Monad
• Solution :
type M t = (t -> Cont) -> Cont
instance Monad M where return a = \c -> c a m >>= k = \c -> m (\a -> k a c)
show :: M Value -> Stringshow m = let v=(m (\x -> x)) in show v
• All the rest are unchanged.
CS5205 Interpreters 37
CPS InterpreterCPS Interpreter
• If we expand CPS monad, we get a CPS interpreter!
interp :: Term -> Environment -> (Value -> Cont) -> Cont
interp (Var x) e = \ c -> lookup x e cinterp (Con i) e = \ c -> c (Num i)interp (Add u v) e = \ c -> inter u e
(\ a -> interp v e(\ b -> add a b c))
interp (Lam x v) e = \ c ->c (Fun (\a -> interp v (x:a):e ))
interp (App u v) e = \ c -> interp u e(\ f -> interp v e(\ b -> apply f b c))
CS5205 Interpreters 38
Call with Current ContinuationCall with Current Continuation
• This is a feature in Scheme that allows a current continuation to be captured or reified.
call/cc h
where h is a function that takes the current continuation as a parameter.
call/cc (\ cc -> body )
An example is below where cc is the captured current continuation
CS5205 Interpreters 39
A Simple ExampleA Simple Example
Add 1 (Call/cc r (Add 2 (r 6)))
• An example in our tiny language
• Captured continuation : \n -> Add 1 n
• Continuation when r was applied to 6 : \n -> Add 2 n
• Final Outcome : Add 1 6 7
CS5205 Interpreters 40
Breaking from a LoopBreaking from a Loop
• The foreach loop iterates over the list and would return the first element found in xs list, or None otherwise :
search :: (a->Bool) -> [a] -> Maybe asearch wanted xs = let _ = foreach (\ element -> if (wanted element) then return (Some element) else () ) xs in None
• A useful command is to break out of a loop:
CS5205 Interpreters 41
Breaking from a Loop with call/ccBreaking from a Loop with call/cc
• When captured continuation is applied, the current continuation is lost!
search :: (a->Bool) -> [a] -> Maybe asearch wanted xs = call/cc (\ ret -> let _ = foreach (\ element -> if (wanted element) then ret (Some element) else () ) xs in None )
• Using call/cc to capture a current context
CS5205 Interpreters 42
Interpreter with call/ccInterpreter with call/cc
• Once interpreter is in CPS style, it is quite easy to provide a call/cc functionality using:
callccK :: ((a -> K b) -> K a) -> K acallccK h = \ c -> let k a = \c2 -> c a
in h k c
• To add call/cc to the interpreted language:
data Term = … | Callcc Name Term
interp (Callcc x v) e = callccK (\k -> interp v
((x,Fun k):e))
CS5205 Interpreters 43
Monads in CPSMonads in CPS
• To achieve the effect of a monad M in CPS, define:
type Cont = M Value
showK n = showM (n return)
n :: K Valuereturn :: Value -> M Value
• CPS interpreter can support modular changes in a similar way as monadic interpreters.
CS5205 Interpreters 44
Monads versus CPSMonads versus CPS
• With monads, we write :
m >>= (\a -> k a)
\ c -> m (\a -> k a c)
• With CPS, one writes:
• Almost equal expressive power, except that monad can be made into an ADT but not continuation.
CS5205 Interpreters 45
Exit Continuation (uses ref type)Exit Continuation (uses ref type)
let return = ref _
(+ 1 (call/cc (\ cont -> return := cont 1)))
• Current continuation can escape call/cc
2
• Invoking out of scope:
return 22 23