Tim Sheard Oregon Graduate Institute

Post on 12-Jan-2016

22 views 0 download

description

Fundamentals of. Staged Computation. Tim Sheard Oregon Graduate Institute. Lecture 3: More Examples. CSE 510 Section FSC Winter 2004. Assignments. The paper DSL Implementation Using Staging and Monads is now officially assigned. See the web page to obtain a copy. - PowerPoint PPT Presentation

Transcript of Tim Sheard Oregon Graduate Institute

Tim SheardOregon Graduate Institute

Lecture 3: More Examples

CSE 510 Section FSCCSE 510 Section FSC

Winter 2004Winter 2004

2Cse583 Winterl 2002

Assignments

The paper DSL Implementation Using Staging and Monads is now officially assigned. See the web page to obtain a copy. A volunteer presenter is needed to

present the paper next Monday.

Homework 2, due in one week, is now assigned. See webpage for details Due in one week, Monday Jan 18

3Cse583 Winterl 2002

An Interesting Note

Some functions are code transformers plus : int -> <int> -> <int> plus x ycode = < ~(lift x) + ~ycode >

Others are code generators plus' : int -> <int -> int> plus' x = <fn y => ~(lift x) + y>

When do we use one? When do we use the other? Are they equivalent?

4Cse583 Winterl 2002

Transformers to generators

Code transformers can be made code generators with a “trick”

fun plus’’ n = <fn y => ~(plus n <y>)>;

-| plus’’ 3;

val it =

<(fn a = 3 %+ a)>

: <int -> int>

5Cse583 Winterl 2002

Another example: two versions

fun add3 0 y = y

| add3 n y = < 1 + ~(add3 (n-1) y)>;

fun add4 0 = <fn y => y>

| add4 n = <fn y => 1 + ~(add4 (n-1)) y>;

6Cse583 Winterl 2002

Exponentially large generated programs

fun even x = (x mod 2) = 0;

fun filter p [] = <[]>

| filter p (x::xs) =

<if ~p ~(lift x)

then ~(filter p xs)

else ~(lift x) :: ~(filter p xs)>;

-| filter <even> [3];

val it =

<if %even 3 then [] else [3]>

: <int list>

Note the repeated, related (here identical)

, recursive calls

7Cse583 Winterl 2002

But let the list grow-| filter <even> [1,2,3,4];val it = <if %even 1 then if %even 2 then if %even 3 then if %even 4 then [] else [4] else 3 :: if %even 4 then [] else [4] else 2 :: if %even 3 then if %even 4 then [] else [4] else 3 :: if %even 4 then [] else [4] else 1 :: if %even 2 then if %even 3 then if %even 4 then [] else [4] else 3 :: if %even 4 then [] else [4] else 2 :: if %even 3 then if %even 4 then [] else [4] else 3 :: if %even 4 then [] else

[4]> : <int list>

8Cse583 Winterl 2002

Use let to share callsfun filter p [] = <[]>

| filter p (x::xs) =

<let val ys = ~(filter p xs)

in if ~p ~(lift x)

then ys

else ~(lift x) :: ys end>;

val ex2 = filter <even> [1,2,3,4];

-| val ex2 =

<let val a = []

val b = if %even 4 then a else 4 :: a

val c = if %even 3 then b else 3 :: b

val d = if %even 2 then c else 2 :: c

in if %even 1 then d else 1 :: d end>

9Cse583 Winterl 2002

Staged Shortest Path

Given a directed weighted graph G=(V,E)Two nodes a,b in V, The shortest path algorithm finds the minimum weighted path in G from the source a to the destination b.Where the weights are given by a weight function W

10Cse583 Winterl 2002

Representing Graphsfun g x =

case x of

1 => [2]

| 2 => [3,4]

| 3 => [5]

| 4 => [1,2,5]

| 5 => [4]

| _ => [];

3

2

1 4

5

11Cse583 Winterl 2002

Structure of functionfun shortestPath succ source dest marked weight = . . .

succ is the function associating to a vertex a list of successor vertexes, and encodes the topology of the graph

source is the source vertex; dest is the destination vertex; marked indicates which nodes have already

been visited by the algorithm; (weight x y) indicates the weight of the

edge (x,y).

12Cse583 Winterl 2002

Helper functions(* min : int -> int -> int *)fun min x z = if x '<' z then x else z ;

(* minimum : int list -> int *)fun minimum (x::xs) = (case xs of [] => x | _ => min x (minimum xs));

(* map : ('b -> 'a) -> 'b list -> 'a list *)fun map f [] = [] | map f (a::b) = (f a)::(map f b);

(* mem : int -> int list -> bool *)fun mem x [] = false | mem x (a::b) = if a=x then true else mem x b;

(* minus : int list -> int list -> int list *)fun minus [] ys = [] | minus (a::b) ys = if mem a ys then minus b ys else a::(minus b ys);

13Cse583 Winterl 2002

shortestPathfun shortestPath succ source dest marked weight =if source = dest then 0 else let val marked2 = (source::marked) val explore = (minus (succ source) marked2) fun short x = shortestPath succ x dest marked2 weight val path_weights = map (fn node => (short node) + (weight source node)) explore in case path_weights of [] => infinity | _ => (minimum path_weights) end;

14Cse583 Winterl 2002

Exampleval ex1 =

let fun weight x y = 1

in shortestPath g 3 2 [] weight end;

-| val ex1 = 3 : int3

2

1 4

5

15Cse583 Winterl 2002

Staging shortestPath The graph is knownThe source and destination are knownThe weight function is dynamic and won’t be known until later.

shortestPath :

graph -> int -> int -> int list ->

(int -> int -> int) -> int

shortestPath2 :

graph -> int -> int -> int list ->

<(int -> int -> int) -> int>

16Cse583 Winterl 2002

Stage helper functions

Staging the minimum function

liftMinimum : <int> list -> <int>

fun liftMinimum x =

case x of

[] => <infinity>

| (c::cs) => <min ~c ~(liftMinimum cs)>;

17Cse583 Winterl 2002

shortestPath2fun shortestPath2 succ source dest marked = <fn weight => ~(if source = dest then <0> else let val marked2 = source::marked val explore = (minus (succ source) marked) fun short x = shortestPath2 succ x dest marked2 val path_weights = map (fn node => < (~(short node) weight) + (weight ~(lift source) ~(lift node)) > ) explore in (liftMinimum path_weights) end ) >;

Note shortestPath2 is

in generator style

18Cse583 Winterl 2002

Results-| val ex2 = (shortestPath2 g 4 2 []);

val ex2 =

<(fn a =>

%min (%min (0 %+ a 1 2) (%infinity %+ a 4 1))

(%min (0 %+ a 4 2)

(%min (%infinity %+ a 4 5)

%infinity)))>

: <(int -> int -> int) -> int>

3

2

1 4

5

19Cse583 Winterl 2002

Unnest the calls to min

fun liftMinimum x =

case x of

[] => <infinity>

| [x] => x

| ( <infinity> :: cs) => liftMinimum cs

| (c::cs) => <let val y = ~(liftMinimum cs)

val z = ~c

in min z y end>;

Note special case for

singleton list

20Cse583 Winterl 2002

shortestPath2 againfun shortestPath2 succ source dest marked = <fn weight =>

~(if source = dest

then <0>

else let val marked2 = source::marked

val explore = (minus (succ source) marked)

fun short x = shortestPath2 succ x dest marked2

val path_weights =

map (fn node =>

let val recall = < ~(short node) weight>

val wght = <weight ~(lift source) ~(lift node)>

in <let val q = ~recall in q + ~wght end>

end)

explore

in (liftMinimum path_weights) end

) >;

Note the generated let

21Cse583 Winterl 2002

Results

val ex2 = (shortestPath2 g 4 2 []);

-| val ex2 =

<(fn a =>

let val b = %infinity %+ a 4 5

val c = 0 %+ a 4 2

val d = %min c b

val e = 0 %+ a 1 2

val f = e %+ a 4 1

in %min f d end)>

: <(int -> int -> int) -> int>

3

2

1 4

5

22Cse583 Winterl 2002

Extended example 2

Staged merge function for sorted listsUn-staged version

fun merge xs ys =

case xs of

[] => ys

| (z::zs) => case ys of

[] => xs

| w::ws => if z '<' (w:int)

then z::(merge zs ys)

else w::(merge xs ws);

Suppose xs is static and ys is dynamic

23Cse583 Winterl 2002

First staged attempt fun merge2 xs =

<fn ys =>

~(case xs of

[] => <ys>

| (z::zs) =>

<case ys of

[] => ~(lift xs)

| (w::ws) =>

if z '<' (w:int)

then z::(~(merge2 zs) ys)

else w::(~(merge2 xs) ws)

>)>;

Goes into an infinite loop. Why?

24Cse583 Winterl 2002

Second AttemptFirst some helper functions

fun reverse [] ys = ys

| reverse (x::xs) ys = (reverse xs (x::ys));

fun split2 (n:int) xs (small,big) =

case xs of

[] => (reverse small [], reverse big [])

| (z::zs) => if z '>' n

then split2 n zs (small,z::big)

else split2 n zs (z::small,big);

fun split n l = (split2 n l ([],[]));

25Cse583 Winterl 2002

Unstaged version using the helper functions

fun merge3 xs ys =

case xs of

[] => ys

| z::zs =>

(case ys of

[] => xs

| w::ws =>

if z '<' w

then z::(merge3 zs ys)

else let val (u,v) = split z ys

in

append u (z::(merge3 zs v))

end

);split avoids recursive

call on xs

u is all elements of

ys less than z

26Cse583 Winterl 2002

Staged Versionfun merge4 xs = <fn ys => ~(case xs of [] => <ys> | (b::bs) => <case ys of [] => ~(lift xs) | (w::ws) => if (~(lift b)) '<' w then (~(lift b))::(~(merge4 bs) ys) else let val (low,high) = split (~(lift b)) ys in append low (~(lift b)::(~(merge4 bs) high)) end >) >;

27Cse583 Winterl 2002

Not so-good, Generated code

-| merge4 [2,5];val it = <(fn a => (case a of [] => [2,5] | (c::b) => if 2 %'<' c then 2 :: (case a of [] => [5] | (k::j) => if 5 %'<' k then 5 :: a else let val (m,l) = %split 5 a in %append m (5 :: l) end) else let val (e,d) = %split 2 a in %append e (2 :: (case d of [] => [5] | (g::f) => if 5 %'<' g then 5 :: d else let val (i,h) = %split 5 d in %append i (5 :: h) end)) end))> : <int list -> int list>

28Cse583 Winterl 2002

Improve by use transformer style use let to share recursive call

fun merge5 xs ys = case xs of [] => ys| (b::bs) => <case ~ys of [] => ~(lift xs) | (w::ws) => let val tail = ~(merge5 bs ys) val (low,high) = split (~(lift b)) ~ys in if (~(lift b)) '<' w then (~(lift b)):: tail else append low (~(lift b):: tail) end >;fun f1 xs = <fn ys => ~(merge5 xs <ys>)>;

29Cse583 Winterl 2002

Better code-| f1 [2,3];val it = <(fn a => (case a of [] => [2,3] | (c::b) => let val d = case a of [] => [3] | (f::e) => let val (h,g) = %split 3 a in if 3 %'<' f then 3 :: a else %append h (3 :: a) end) val (j,i) = %split 2 a in if 2 %'<' c then 2 :: d else %append j (2 :: d) end))>

30Cse583 Winterl 2002

ReviewMultiple stage programs require nested brackets. Transformer style is often useful.Staged helper functions are often necessary.Generated programs must follow all paths of a generated if or case, even if the unstaged version will follow only one path.

Leads to possiblility of exponentially growing code. Can cause the generator not to terminate if recursive call

at first level doesn’t “get smaller”, even though it gets smaller (in the second stage) in the unstaged program.

Use let to share similar or related code to avoid this blowup.

Use let to avoid deeply nested function calls. Simplifies the structure, and won’t blow up the object level compiler by generating code in weird ways.