1 / 45

CS5205: Foundations in Programming Languages

CS5205: Foundations in Programming Languages. Interpreters. Interpreters. 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

xiu
Download Presentation

CS5205: Foundations in Programming Languages

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. CS5205: Foundations in Programming Languages Interpreters. Interpreters

  2. Interpreters • 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 Interpreters

  3. Topics • 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 Interpreters

  4. Simple Language • Abstract syntax tree data Term = Var Name | Con Int | Add Term Term | Lam Name Term | App Term Term type Name = String • Lambda calculus plus integer and addition Interpreters

  5. Environment type Env = [(Name,Value)] • Interpreter interp :: Term -> Env -> Value Simple Interpreter • Value of Language data Value = Wrong | Num Int | Fun (Value -> Value) Term Value interp Env Interpreters

  6. Displaying a given value instance Show Value where show Wrong = "<wrong>" show (Num i) = show i show (Fun f) = "<function>" Direct-Style Interpreter • Looking up environment lookup :: Name -> Environment -> Value lookup x [] = Wrong lookup x ((y,b):r) = if x==y then b else lookup x r Interpreters

  7. Direct-Style Interpreter • Main interpreter interp :: Term -> Environment -> Value interp (Var x) e = lookup x e interp (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) Interpreters

  8. Applying a function to its argument apply :: Value -> Value -> Value apply (Fun k) a = k a apply _ _ = Wrong Direct-Style Interpreter • Adding two numbers add :: Value -> Value -> Value add (Num i) (Num j) = (Num (i+j)) add _ _ = Wrong Interpreters

  9. 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? Interpreters

  10. that satisfies three laws: i :o x = x x :o i = x x :o (y :o z) = (x :o y) :o z Monoids vs Monads • Recall that monoid M is a triple: ( M, i :: M, :o :: M -> M -> M ) Interpreters

  11. that satisfy three laws: (return a) >>= k = k a m >>= return = m m >>= (\a -> (k a) >>= (\b -> h b)) = (m >>= (\a -> k a)) >>= (\b -> h b) Monoids vs Monads • Similarly, monad M is a more complex triple: ( M, return :: a -> M a, >>= :: M a -> (a -> M b) -> M b ) Interpreters

  12. Monadic Interpreter • We can implement our interpreter using monadic style. interp :: Term -> Environment -> M Value interp (Var x) e = lookup x e interp (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) Interpreters

  13. Modified value type data Value = Wrong | Num Int | Fun (Value -> M Value) Monadic Interpreter • Looking up environment lookup :: Name -> Environment -> M Value lookup x [] = return Wrong lookup x ((y,b):r) = if x==y then return b else lookup x r Interpreters

  14. Applying a function to its argument apply :: Value -> Value -> M Value apply (Fun k) a = k a apply _ _ = return Wrong Monadic Interpreter • Adding two numbers add :: Value -> Value -> M Value add (Num i) (Num j) = return (Num (i+j)) add _ _ = return Wrong Interpreters

  15. Using an isomorphic data declaration : data M t = Id t instance Monad M where return a = Id a (Id m) >>= k = (k m) Monadic Interpreter • Identity Monad type M t = t instance Monad M where return a = a m >>= k = (k m) Interpreters

  16. Adding Error Message • To provide more meaningful error messages, we can use a new monad. data E t = Success t | Error String type 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 Interpreters

  17. Applying a function to its argument apply :: Value -> Value -> M Value apply (Fun k) a = k a apply f _ = errorM “Argument “ ++show f++” must be a function” Change Wrong to Error Messages • Adding two numbers add :: Value -> Value -> M Value add (Num i) (Num j) = return (Num (i+j)) add a b = errorM “Adding “++ show i++show j ++ “:should be numbers!” Interpreters

  18. Modified value type data Value = Num Int | Fun (Value -> M Value) Change Wrong to Error Messages • Looking up environment lookup :: Name -> Environment -> M Value lookup x [] = errorM “Unknown Var” ++ show x lookup x ((y,b):r) = if x==y then return b else lookup x r Interpreters

  19. Adding Error Message with Position • To provide more meaningful error messages, we can use a new monad. data E t = Success t | Error String type M t = Position -> E t type 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)) Interpreters

  20. Key changes to Interpreter interp :: Term -> Environment -> M Value interp (At p t) e = resetP p (interp t e) resetP :: Position -> M a -> M a resetP q m = (\p -> (m q)) Language with Position • Abstract syntax tree data Term = Var Name | Con Int | Add Term Term | Lam Name Term | App Term Term | At Position Term Interpreters

  21. 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) Interpreter with States • Assume we wish to keep track of the number of additions and applications performed by a given interpreter. Interpreters

  22. Update state by: tickS :: M () tickS = \s -> (s+1,()) clearS :: M () clearS = \s -> (0,()) Interpreter with States • Read state by: getState :: M State getState = \s -> (s,s) Interpreters

  23. Changes 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) Interpreters

  24. Topics • Monadic Interpreter • Error messages with positions • States • Output • Non-determinism • Call-by-Value vs Call by Name • CPS vs Monads Interpreters

  25. Interpreter 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 Interpreters

  26. Key changes to Interpreter interp :: Term -> Environment -> M Value interp (Out t) e = do v <- (interp t e) outM v return v outM :: Value -> M () outM v = (show v++” ;”, ()) Language with Output • Abstract syntax tree data Term = Var Name | … | Out Term Interpreters

  27. 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. Non-Deterministic Language • We may have a non-determinstic operator data Term = Var Name | … | Fail | Amb Term Term Interpreters

  28. Non-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 Interpreters

  29. Changes 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 Interpreters

  30. Topics • Monadic Interpreter • Error messages with positions • States • Output • Non-determinism • Call-by-Value vs Call by Name • CPS vs Monads Interpreters

  31. To make into call-by-name interpreter, change : 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) Call-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) Interpreters

  32. Call-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 Interpreters

  33. Doubling a number would be: double :: Int -> (Int -> Cont) -> Cont double x c = add x x c 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) -> Cont add x y c = c (x+y) sub,mult :: Int -> Int -> (Int -> Cont) -> Cont eq :: Int -> Int -> (Bool -> Cont) -> Cont Interpreters

  34. More religiously: fact :: Int -> (Int -> Cont) -> Cont fact n c = eq n 0 (\b -> if b then c 1 else sub n 1 (\m -> fact m (\ r -> mult n r c))) Continuation-Passing Style (CPS) • How about CPS-style for factorial. fact :: Int -> (Int -> Cont) -> Cont fact n c = if n==0 then c 1 else fact (n-1) (\ r -> c (n*r)) Interpreters

  35. Continuation-Passing Style (CPS) • Advantages: • tail-recursive code • better modularity for easier code changes • Disadvantage • harder to read (higher-order) Interpreters

  36. CPS 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 -> String show m = let v=(m (\x -> x)) in show v • All the rest are unchanged. Interpreters

  37. CPS 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 c interp (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)) Interpreters

  38. An example is below where cc is the captured current continuation call/cc (\ cc -> body ) Call 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. Interpreters

  39. Captured continuation : \n -> Add 1 n • Continuation when r was applied to 6 : • \n -> Add 2 n • Final Outcome : Add 1 6  7 A Simple Example • An example in our tiny language Add 1 (Call/cc r (Add 2 (r 6))) Interpreters

  40. Breaking from a Loop • A useful command is to break out of a loop: search :: (a->Bool) -> [a] -> Maybe a search wanted xs = let _ = foreach (\ element -> if (wanted element) then return (Some element) else () ) xs in None • The foreach loop iterates over the list and would return the first element found in xs list, or None otherwise : Interpreters

  41. Breaking from a Loop with call/cc • Using call/cc to capture a current context search :: (a->Bool) -> [a] -> Maybe a search wanted xs = call/cc (\ ret -> let _ = foreach (\ element -> if (wanted element) then ret (Some element) else () ) xs in None ) • When captured continuation is applied, the current continuation is lost! Interpreters

  42. 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)) Interpreter 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 a callccK h = \ c -> let k a = \c2 -> c a in h k c Interpreters

  43. Monads in CPS • To achieve the effect of a monad M in CPS, define: type Cont = M Value showK n = showM (n return) n :: K Value return :: Value -> M Value • CPS interpreter can support modular changes in a similar way as monadic interpreters. Interpreters

  44. With CPS, one writes: \ c -> m (\a -> k a c) Monads versus CPS • With monads, we write : m >>= (\a -> k a) • Almost equal expressive power, except that monad can be made into an ADT but not continuation. Interpreters

  45. Invoking out of scope: return 22  23 Exit Continuation (uses ref type) • Current continuation can escape call/cc let return = ref _ (+ 1 (call/cc (\ cont -> return := cont 1)))  2 Interpreters

More Related