1 / 33

Advanced Functional Programming

Advanced Functional Programming. Tim Sheard Oregon Graduate Institute of Science & Technology. Lecture: Staged computation Difference between Haskell and ML Intro to MetaML Using staging to control evaluation order. type variables and type application 'a Tree type constructors

caryne
Download Presentation

Advanced Functional Programming

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. Advanced Functional Programming • Tim Sheard • Oregon Graduate Institute of Science & Technology • Lecture: Staged computation • Difference between Haskell and ML • Intro to MetaML • Using staging to control evaluation order

  2. type variables and type application 'a Tree type constructors int, string, bool tuples (int * string * int) type variables and type application Tree a type constructors Int, String, Bool tuples (Int, String, Bool) Differences in Types

  3. (* Data definitions *) datatype 'a Tree = Tip of 'a | Fork of ('a Tree)*('a Tree) 'a = type variable constructors are not capitalized -- data definitions data Tree a = Tip a | Fork (Tree a) (Tree a) Differences comments Type constructors are post fix note use of "of" constructor functions are always uncurried (use tuples)

  4. (* function definitions *) fun fact n = if n=0 then 1 else n * (fact (n-1)); fun depth (Tip a) = 0 | depth (Fork(x,y)) = 1 + max (depth x, depth y); -- function definitions fact n = if n==0 then 1 else n * (fact (n-1)) depth (Tip a) = 0 depth (Fork x y) = 1 + max (depth x) (depth y) difference 2 note use of "fun" equality is double = use "bar" (|) to separate clauses primitives more likely to be curried in Haskell

  5. Data List a = [] | (:) a (list a) map f [] = [] map f (x:xs)=(f x):(map f xs) pi = 3.14159 \ x -> x + 1 Datatype ‘a list = [] | (op ::) of ‘a * (‘a list) fun map f [] = … | map f (x::xs) = val pi = 3.14159 fn x => x + 1 Differences between Haskell & ML

  6. - op +; val it = fn:int * int -> int - op *; val it = fn:int * int -> int - op -; val it = fn:int * int -> int - op @; val it = fn:'a list * 'a list -> 'a list - length; val it = fn:'a list -> int - op ::; val it = fn:'a * 'a list -> 'a list - hd; val it = fn:'a list -> 'a - tl; val it = fn:'a list -> 'a list Main> :t (+) (+) :: Num a => a -> a -> a Main> :t (*) (*) :: Num a => a -> a -> a Main> :t (-) (-) :: Num a => a -> a -> a Main> :t (++) (++) :: [a] -> [a] -> [a] Main> :t length length :: [a] -> Int Main> :t (:) (:) :: a -> [a] -> [a] Main> :t head head :: [a] -> a Main> :t tail tail :: [a] -> [a] Some Primitives

  7. (* variable definition *) val tree1 = Fork(Fork(Tip 1,Tip 2), Tip 3); -- variable definition tree1 = Fork (Fork (Tip 1) (Tip 2)) (Tip 3) Differences 3 use val to declare variables

  8. fn x => x + 1 let fun f x = x + 1 in f 7 end has type in ML is : datatype T = ... datatype ('a,'b) T = ... = (in MetaML only) 'a ('b T) \ x -> x + 1 let f x = x + 1 in f 7 has type in Haskell is :: data T = ... data T b a = ... functions

  9. case x of [] => 5 | (x::xs) => len xs + m3 case x of [] -> 5 (x:xs) -> len xs + m3 case expressions

  10. (* booleans *) - true; val it = true : bool - false; val it = false : bool (* mutual recursion *) fun even 0 = true | even n = odd (n-1) and odd 0 = false | odd n = even (n-1); -- booleans Main> :t True True :: Bool Main> :t False False :: Bool -- mutual recursion even 0 = True even n = odd (n-1) odd 0 = False odd n = even (n-1) Differences 4 No capitals all functions are implicitly mutually recursive use of "and" must separate mutually recursive functions

  11. Intro to MetaML

  12. Controlling Evaluation Order • We want more than just the correct result! • We want to control other resources such as time and space without resorting to tricks or unnatural programming styles. • Mechanism - Control Evaluation Order

  13. Traditional Approaches • Fixed evaluation order with language extensions • Lazy - Outermost • add strictness annotations • Strict - Innermost • add annotations like force and delay • Encode laziness using lambda in a strict setting • datatype 'a lazylist = • lazyNil • | lazyCons of 'a * (unit -> 'a lazylist); • fun count n = lazyCons(n, fn () => count (n+1))

  14. Limitations • None of these approaches allow computation under a lambda! This is sometimes just what is needed. For example: • fun power n = • (fn x => if n=0 • then 1 • else x * (power (n-1) x)) • power 2;

  15. Example reduction • (power 2) • unfold the definition • (fn x => if 2=0 then 1 else x * (power (2-1) x)) • perform the if, under the lambda • (fn x => x * (power (2-1) x)) • unfold power again • (fn x => x * ((fn x => if 1=0 • then 1 • else x * (power (1-1) x)) • x)) • use the beta rule to apply the explicit lambda to x

  16. Example (cont.) • (fn x => x * (if 1=0 then 1 else x * (power (1-1) x))) • perform the if • (fn x => x * (x * (power (1-1) x))) • unfold power again • (fn x => x * (x * ((fn x => if 0=0 • then 1 • else x * (power (0-1) x))) • x)) • use the beta rule to apply the explicit lambda to x • (fn x => x * (x * (if 0=0 then 1 • else x * (power (0-1) x)))) • perform the if • (fn x => x * (x * 1))

  17. Solution - Use richer annotations • Brackets: < e > • no reductions allowed in e • delay computation • if e:t then <e> : <t> (pronounced code of t) • Escape: ~ e • relax the no reduction rule of brackets above • Escape may only occur inside Brackets • splice code together to build larger code • Run: run e • remove outermost brackets • force computations which have been delayed

  18. Calculus • A calculus describes equivalences between program fragments. • The rules of a calculus can be applied in any order. • An implementation applies the rules in some fixed order. • Traditional rules • beta – (fn x => e) v  e[v/x] • if – if true then x else y  x • – if false then x else y  y • delta – 5 + 2  7

  19. Rules for code • Introduction rule for code • < e > • 1st elimination rule for code (escape-bracket elim) • < … ~<e> … > ---> < … e … > • ~<e> must appear inside enclosing brackets • e must be escape free • <e> must be at level 0 • 2nd elimination rule for code (run-bracket elim) • run <e> ---> e • providedehas no escapes • the whole expression is at level 0

  20. Power example revisited • (* power : int -> <int> -> <int> *) • fun power n = • fn x => if n=0 • then <1> • else < ~x * ~(power (n-1) x) > • (* ans : < int -> int > *) • val ans = < fn z => ~(power 2 <z>) >;

  21. <fn z => ~ (power 2 <z>) > <fn z => ~(if 2=0 then <1> else < ~<z> * ~(power (2-1) <z>) >)> <fn z => ~< ~<z> * ~(power (2-1) <z>) >>) <fn z => ~< z * ~(power (2-1) <z>) >>) <fn z => ~< z * ~(if 1=0 then <1> else < ~<z> * ~(power (1-1) <z>) >) >>)

  22. <fn z => ~< z * ~< ~<z> * ~(power (1-1) <z>) >>> <fn z => ~< z * ~< z * ~(power (1-1) <z>) >>> <fn z => ~< z * ~< z * ~(power 0 <z>) >>> <fn z => ~< z * ~< z * ~<1> >>> <fn z => ~< z * ~< z * 1 >>> <fn z => ~< z * z * 1 >> <fn z => z * z * 1>

  23. MetaML: Meta-programming • Meta-Programming: Programs that write programs • What Infrastructure is possible in a language designed to help support the algorithmic construction of other programs? • Advantages of meta-programs • capture knowledge • efficient solutions • design ideas can be communicated and shared

  24. Types of meta-programs • Static generators • Generate code which is then “written to disk” and processed by normal compilers etc. • Two kinds • Homogeneous systems • object language = meta-language • Heterogeneous systems • object-language different from meta-language • Run-time generators • Staged Programs • Programs that generate other programs, and then execute the programs they generated • MetaML is a staged programming language which does run-time code generation

  25. MetaML & the Mustang Project • Theory • Semantics of staged programs • What does it mean to have a staged program? • How can we tell if a staged program computes the same result as its unstaged counterpart? • Calculus of programs - Rules for reasoning • Staged type systems • A static type system keeps bad programs from executing by throwing away bad programs by refusing to compile them. • A staged program admits more bad things. • E.g. using a variable before it is defined, or executing a program before its complete, for example. • Staged languages need richer type systems to throw away these bad programs. • Automatic staging • partial evaluation

  26. MetaML & the Mustang Project • Tools • Staged Languages • MetaML • reflective: obj-lang = meta-lang = ML • multi-stage • Heterogeneous (meta-lang=ML, obj-lang varies, 2 stage)

  27. Building pieces of code • -| <23>; • val it = <23> : <int> • -| <length [1,2,3]>; • val it = <%length [1,2,3]> :<int> • -| <23 + 5>; • val it = <23 %+ 5> : <int> • -| <fn x => x + 5>; • val it = <(fn a => a %+ 5)> : <int -> int> • -| <fn x => <x + 1>>; • val it = <(fn a => <a %+ 1>)> : <int -> <int>>

  28. Let’s try it ! Run MetaML

  29. Composing pieces of code • -| val x = <2>; • val x = <2> : <int> • -| val y = <44 + ~x>; • val y = <44 %+ 2> : <int> • -| fun pair x = <( ~x, ~x )>; • val pair = Fn : ['b].<'b > -> <('b * 'b )> • -| pair <11>; • val it = <(11,11)> : <(int * int)>

  30. Executing constructed code • -| val x = <34 + 2>; • val x = <34 %+ 2> : ['a].<int> • -| run x; • val it = 36 : int • -| fun id x = x; • val id = Fn : ['a].'a -> 'a • -| val q = <1 + ~(id <2+3>) >; • val q = <1 %+ 2 %+ 3> : <int> • -| run q; • val it = 6 : int

  31. Multi-stage code • -| val z = <fn n => <n + 1>>; • val z = <(fn a => <a %+ 1>)> : <int -> <int>> • -| val f = run z; • val f = Fn : int -> <int> • -| f 12; • val it = <%n %+ 1> : <int> • -| run it; • val it = 13 : int

  32. The lift operator • -| <4+1>; • val it = <4 %+ 1> : <int> • -| lift (4+1); • val it = <5> : <int> • -| val z = <fn n => < ~(lift n) + 1>>; • val z = <(fn a => <~(lift a) %+ 1>)> :<int -> <int>> • -| run z; • val it = Fn : int -> <int> • -| it 5; • val it = <5 %+ 1>: <int> • -| run it; • val it = 6 : int

  33. Lift v.s. lexical capture • Lift cannot be used on functions • -| lift id; • Error: The term: id • Non Qualified type, not liftable: ? -> ? • Lift makes code readable • -| fun f x = <(x, ~(lift x))>; • val f = Fn : ['b^].'b -> <('b * 'b )> • -| f 3; • val it = <(%x,3)> : <(int * int)> • Lexical capture is more efficient • -| lift [1+3,4,8-4]; • val it = <4 :: (4 :: (4 :: [])))> : <int list >

More Related