Last time: generic programming val show : a data a string 1/ 45 - - PowerPoint PPT Presentation

last time generic programming
SMART_READER_LITE
LIVE PREVIEW

Last time: generic programming val show : a data a string 1/ 45 - - PowerPoint PPT Presentation

Last time: generic programming val show : a data a string 1/ 45 This time: staging . < e > . 2/ 45 Review: abstraction Lambda abstraction Abstraction of type equalities x : A . M A :: K . M a b A :: K . B


slide-1
SLIDE 1

Last time: generic programming

val show : ’a data → ’a → string

1/ 45

slide-2
SLIDE 2

This time: staging

.< e >.

2/ 45

slide-3
SLIDE 3

Review: abstraction

Lambda abstraction λx : A.M ΛA :: K.M λA :: K.B First-class ∀ and ∃

type t = { f: ’a. . . . } type t = E : ’a s → t

Modular abstraction

module F(X : T) = . . .

Abstraction of type equalities

a ≡ b

Interfaces to computation

m > > = k f ⊗ p f > > > g

Abstraction over data shape

val show : ’a data → ’a → string

3/ 45

slide-4
SLIDE 4

The cost of ignorance

Fewer opportunities for optimization

let both_eq1 : int * int → int * int → bool = fun (x1 , y1) (x2 , y2) → x1 = x2 && y1 = y2 let both_eq2 : (int → int → bool) → int * int → int * int → bool = fun eq (x1 , y1) (x2 , y2) → eq x1 x2 && eq y1 y2 both_eq2 (fun x y → x = y) type eq = { eq: ’a. ’a → ’a → bool } let both_eq {eq} (x1 , y1) (x2 , y2) = eq x1 x2 && eq y1 y2

4/ 45

slide-5
SLIDE 5

The cost of ignorance

Interpretative overhead

let print_int_pair (x,y) = print_char ’(’; print_int x; print_char ’,’; print_int y; print_char ’)’ let print_int_pair2 (x,y) = Printf.sprintf "(%d,%d)" x y let print_int_pair3 (x,y) = print_string (gshow (pair int int) (x, y))

5/ 45

slide-6
SLIDE 6

Abstraction wants to be free

let pow2 x = x * x (* x2 *) let pow3 x = x * x * x (* x3 *) let pow5 x = x * x * x * x * x (* x5 *) let rec pow x n = (* xn *) if n = 0 then 1 else x * pow x (n - 1) val pow : int → int → int

6/ 45

slide-7
SLIDE 7

Power, staged

let rec pow x n = if n = 0 then .< 1 >. else .<.~ x * .~ (pow x (n - 1)) >.

7/ 45

slide-8
SLIDE 8

Power, staged

let rec pow x n = if n = 0 then .< 1 >. else .<.~ x * .~ (pow x (n - 1)) >. val pow : int code → int → int code

8/ 45

slide-9
SLIDE 9

Power, staged

let rec pow x n = if n = 0 then .< 1 >. else .<.~ x * .~ (pow x (n - 1)) >. val pow : int code → int → int code let pow_code n = .< fun x → .~ (pow .<x>. n) >.

9/ 45

slide-10
SLIDE 10

Power, staged

let rec pow x n = if n = 0 then .< 1 >. else .<.~ x * .~ (pow x (n - 1)) >. val pow : int code → int → int code let pow_code n = .< fun x → .~ (pow .<x>. n) >. val pow_code : int → (int → int) code

10/ 45

slide-11
SLIDE 11

Power, staged

let rec pow x n = if n = 0 then .< 1 >. else .<.~ x * .~ (pow x (n - 1)) >. val pow : int code → int → int code let pow_code n = .< fun x → .~ (pow .<x>. n) >. val pow_code : int → (int → int) code # pow_code 3;; .< fun x → x * x * x * 1 >.

11/ 45

slide-12
SLIDE 12

Power, staged

let rec pow x n = if n = 0 then .< 1 >. else .<.~ x * .~ (pow x (n - 1)) >. val pow : int code → int → int code let pow_code n = .< fun x → .~ (pow .<x>. n) >. val pow_code : int → (int → int) code # pow_code 3;; .< fun x → x * x * x * 1 >. # let pow3 ’ = !. (pow_code 3);; val pow3 ’ : int → int = <fun >

12/ 45

slide-13
SLIDE 13

Power, staged

let rec pow x n = if n = 0 then .< 1 >. else .<.~ x * .~ (pow x (n - 1)) >. val pow : int code → int → int code let pow_code n = .< fun x → .~ (pow .<x>. n) >. val pow_code : int → (int → int) code # pow_code 3;; .< fun x → x * x * x * 1 >. # let pow3 ’ = !. (pow_code 3);; val pow3 ’ : int → int = <fun > # pow3 ’ 4;;

  • : int = 64

13/ 45

slide-14
SLIDE 14

MetaOCaml basics

14/ 45

slide-15
SLIDE 15

Quoting

let x = "w" in let y = "x" in print_string (x ^ y) let x = "w" in let y = x in print_string (x ^ y) let x = "w" in let y = x in print_string ("x ^ y") let x = "w" in let y = x in print_string ("x" ^ y)

Quoting prevents evaluation.

15/ 45

slide-16
SLIDE 16

Quoting code

MetaOCaml: multi-stage programming with code quoting. Stages: current (available now) and delayed (available later). (Also double-delayed, triple-delayed, etc.)

Brackets

.<e>.

Escaping (within brackets)

.~ e

Running code

!. e

Cross-stage persistence

.<x>.

16/ 45

slide-17
SLIDE 17

Quoting and escaping: some examples

.<3 >. .<1 + 2 >. .<[1; 2; 3] >. .<x + y >. .<fun x → x >. .<(.~f) 3 >. .<.~(f 3)>. .<fun x → .~(f .< x >.) >.

17/ 45

slide-18
SLIDE 18

Quoting: typing

Γ ⊢n e : τ Γ ⊢n+ e : τ T-bracket Γ ⊢n .<e>. : τ code Γ ⊢n e : τ code T-escape Γ ⊢n+ .~e : τ Γ+ ⊢n e : τ code T-run Γ ⊢n !. e : τ Γ(x) = τ (n−m) T-var Γ ⊢n : τ

18/ 45

slide-19
SLIDE 19

Quoting: open code

Open code

let pow_code n = .< fun x → .~ (pow .<x>. n) >.

Cross-stage persistence

let print_int_pair (x,y) = Printf.printf "(%d,%d)" x y let pairs = .< [(3, 4); (5, 6)] >. .< List.iter print_int_pair .~pairs >.

19/ 45

slide-20
SLIDE 20

Quoting: scoping

Scoping is lexical, just as in OCaml.

.< fun x → .~ ( let x = 3 in .<x>. ) >. let x = 3 in .< fun x → .~ ( .<x>. ) >.

MetaOCaml renames variables to avoid clashes:

.< let x = 3 in .~ (let y = .<x>. in .< fun x → .~ y + x >. ) >.

20/ 45

slide-21
SLIDE 21

Quoting: scoping

Scoping is lexical, just as in OCaml.

.< fun x → .~ ( let x = 3 in .<x>. ) >. let x = 3 in .< fun x → .~ ( .<x>. ) >.

MetaOCaml renames variables to avoid clashes:

# .< let x = 3 in .~ (let y = .<x>. in .< fun x → .~ y + x >.) >. ;;

  • : (int → int) code =

.< let x_1 = 3 in fun x_2 → x_1 + x_2 >.

21/ 45

slide-22
SLIDE 22

Learning from mistakes

22/ 45

slide-23
SLIDE 23

Error: quoting nonsense

.< 1 + "two" >.

23/ 45

slide-24
SLIDE 24

Error: quoting nonsense

# .< 1 + "two" >. ;; Characters 7-12: .< 1 + "two" >. ;; ^^^^^ Error: This expression has type string but an expression was expected of type int

24/ 45

slide-25
SLIDE 25

Error: looking into the future

.< fun x → .~ ( x ) >.

25/ 45

slide-26
SLIDE 26

Error: looking into the future

# .< fun x → .~ ( x ) >. ;; Characters 14 -19: .< fun x → .~ ( x ) >. ;; ^^^^^ Wrong level: variable bound at level 1 and used at level 0

26/ 45

slide-27
SLIDE 27

Error: escape from nowhere

let x = .< 3 >. in .~ x

27/ 45

slide-28
SLIDE 28

Error: escape from nowhere

# let x = .< 3 >. in .~ x;; Characters 22 -23: let x = .< 3 >. in .~ x;; ^ Wrong level: escape at level 0

28/ 45

slide-29
SLIDE 29

Error: running open code

.< fun x → .~(!. .<x>. ) >.

29/ 45

slide-30
SLIDE 30

Error: running open code

# .< fun x → .~(!. .<x>. ) >. ;; Exception: Failure "The code built at Characters 7-8:\n .< fun x → .~(!. .< x >. ) >.;;\n ^\n is not closed: identifier x_2 bound at Characters 7-8:\n .< fun x → .~(!. .< x >. ) >.;;\n ^\n is free ".

30/ 45

slide-31
SLIDE 31

Learning by doing

31/ 45

slide-32
SLIDE 32

Power again

Reducing the number of multiplications: x0 = 1 x2n+2 = (xn+1)2 x2n+1 = x(x2n)

let even x = x mod 2 = 0 let sqr x = x * x let rec pow x n = if n = 0 then 1 else if even n then sqr (pow x (n / 2)) else x * pow (n - 1) x

32/ 45

slide-33
SLIDE 33

Power again, staged

Reducing the number of multiplications: x0 = 1 x2n+2 = (xn+1)2 x2n+1 = x(x2n)

let even x = x mod 2 = 0 let sqr x = .< let y = .~ x in y * y >. let rec pow ’ x n = if n = 0 then .<1>. else if even n then sqr (pow ’ x (n / 2)) else .<.~ x * .~ (pow ’ x (n - 1)) >.

33/ 45

slide-34
SLIDE 34

Power again, staged

let rec pow ’ x n = if n = 0 then .<1>. else if even n then sqr (pow ’ x (n / 2)) else .<.~ x * .~ (pow ’ x (n - 1)) >.

34/ 45

slide-35
SLIDE 35

Power again, staged

let rec pow ’ x n = if n = 0 then .<1>. else if even n then sqr (pow ’ x (n / 2)) else .<.~ x * .~ (pow ’ x (n - 1)) >. val pow ’ : int code → int → int code

35/ 45

slide-36
SLIDE 36

Power again, staged

let rec pow ’ x n = if n = 0 then .<1>. else if even n then sqr (pow ’ x (n / 2)) else .<.~ x * .~ (pow ’ x (n - 1)) >. val pow ’ : int code → int → int code let pow_code ’ n = .< fun x → .~ (pow ’ .<x>. n) >.

36/ 45

slide-37
SLIDE 37

Power again, staged

let rec pow ’ x n = if n = 0 then .<1>. else if even n then sqr (pow ’ x (n / 2)) else .<.~ x * .~ (pow ’ x (n - 1)) >. val pow ’ : int code → int → int code let pow_code ’ n = .< fun x → .~ (pow ’ .<x>. n) >. val pow_code ’ : int → (int → int) code

37/ 45

slide-38
SLIDE 38

Power again, staged

let rec pow ’ x n = if n = 0 then .<1>. else if even n then sqr (pow ’ x (n / 2)) else .<.~ x * .~ (pow ’ x (n - 1)) >. val pow ’ : int code → int → int code let pow_code ’ n = .< fun x → .~ (pow ’ .<x>. n) >. val pow_code ’ : int → (int → int) code # pow_code ’ 5;;

  • : (int → int) code =

.< fun x → x * (let y = let y’ = x * 1 in y’ * y’ in y * y) >.

38/ 45

slide-39
SLIDE 39

The staging process, idealized

  • 1. Write the program as usual:

val program : t_sta → t_dyn → t

39/ 45

slide-40
SLIDE 40

The staging process, idealized

  • 1. Write the program as usual:

val program : t_sta → t_dyn → t

  • 2. Add staging annotations:

val staged_program : t_sta → t_dyn code → t code

39/ 45

slide-41
SLIDE 41

The staging process, idealized

  • 1. Write the program as usual:

val program : t_sta → t_dyn → t

  • 2. Add staging annotations:

val staged_program : t_sta → t_dyn code → t code

  • 3. Compile using back:

val back: (’a code → ’b code) → (’a → ’b) code val code_generator : t_sta → (t_dyn → t)

39/ 45

slide-42
SLIDE 42

The staging process, idealized

  • 1. Write the program as usual:

val program : t_sta → t_dyn → t

  • 2. Add staging annotations:

val staged_program : t_sta → t_dyn code → t code

  • 3. Compile using back:

val back: (’a code → ’b code) → (’a → ’b) code val code_generator : t_sta → (t_dyn → t)

  • 4. Construct static inputs:

val s : t_sta

39/ 45

slide-43
SLIDE 43

The staging process, idealized

  • 1. Write the program as usual:

val program : t_sta → t_dyn → t

  • 2. Add staging annotations:

val staged_program : t_sta → t_dyn code → t code

  • 3. Compile using back:

val back: (’a code → ’b code) → (’a → ’b) code val code_generator : t_sta → (t_dyn → t)

  • 4. Construct static inputs:

val s : t_sta

  • 5. Apply code generator to static inputs:

val specialized_code : (t_dyn → t) code

39/ 45

slide-44
SLIDE 44

The staging process, idealized

  • 1. Write the program as usual:

val program : t_sta → t_dyn → t

  • 2. Add staging annotations:

val staged_program : t_sta → t_dyn code → t code

  • 3. Compile using back:

val back: (’a code → ’b code) → (’a → ’b) code val code_generator : t_sta → (t_dyn → t)

  • 4. Construct static inputs:

val s : t_sta

  • 5. Apply code generator to static inputs:

val specialized_code : (t_dyn → t) code

  • 6. Run specialized code to build a specialized function:

val specialized_function : t_dyn → t

39/ 45

slide-45
SLIDE 45

Inner product

let dot : int → float array → float array → float = fun n l r → let rec loop i = if i = n then 0. else l.(i) *. r.(i) +. loop (i + 1) in loop 0

40/ 45

slide-46
SLIDE 46

Inner product, loop unrolling

let dot ’ : int → float array code → float array code → float code = fun n l r → let rec loop i = if i = n then .< 0. >. else .< ((.~l).(i) *. ( .~r).(i)) +. .~ (loop (i + 1)) >. in loop 0

41/ 45

slide-47
SLIDE 47

Inner product, loop unrolling

# .< fun l r → .~ (dot ’ 3 .<l>..<r>. ) >. ;;

  • : (float

array → float array → float) code = .< fun l r → (l.(0) *. r.(0)) +. ((l.(1) *. r.(1)) +. ((l.(2) *. r.(2)) +. 0.)) >.

42/ 45

slide-48
SLIDE 48

Inner product, eliding no-ops

let dot ’’ : float array → float array code → float code = fun l r → let n = Array.length l in let rec loop i = if i = n then .< 0. >. else match l.(i) with 0.0 → loop (i + 1) | 1.0 → .<( .~r).(i) +. .~ (loop (i + 1)) >. | x → .<(x *. ( .~r).(i)) +. .~ (loop (i + 1)) >. in loop 0

43/ 45

slide-49
SLIDE 49

Inner product, eliding no-ops

# .< fun r → .~ (dot ’’ [| 1.0; 0.0; 3.5 |] .<r>. ) >. ;;

  • : (float

array → float) code = .< fun r → r.(0) +. ((3.5 *. r.(2)) +. 0.) >.

44/ 45

slide-50
SLIDE 50

Binding-time analysis

Classify variables into dynamic (’a code) / static (’a)

let dot ’ : int → float array code → float array code → float code = fun n l r →

dynamic: l, r static: n Classify expressions into static (no dynamic variables) / dynamic

if i = n then 0 else l.(i) *. r.(i)

dynamic: l.(i) *. r.(i) static: i = n Goal: reduce static expressions during code generation.

45/ 45