Tim Sheard Oregon Graduate Institute Lecture 5: Review of homework 2 CS510 Sect FSC Winter 2004...

Preview:

Citation preview

Tim SheardOregon Graduate Institute

Lecture 5: Review of homework 2

CS510 Sect FSCCS510 Sect FSC

Winter 2004Winter 2004

2Cse583 Winterl 2002

Discussion of homework 2We haveadd : int -> int -> int

mult : int -> int -> int

member : ['a=].'a list -> 'a -> bool

dotprod : int -> int list -> int list -> int

We wantadd' : int -> <int> -> <int>

mult' : int -> <int -> int>

member' : 'a list -> <'a> -> <bool>

dotprod' int -> int list -> <int list -> int>

3Cse583 Winterl 2002

Add

Have: add : int -> int -> int

Want: add' : int -> <int> -> <int>

fun add 0 y = y

| add n y = 1 + (add (n-1) y);

fun add' 0 y = y

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

Example-| add' 3 <2>;

val it = <1 %+ 1 %+ 1 %+ 2> : <int>

4Cse583 Winterl 2002

mult Have: mult : int -> int -> int Want: mult' : int -> <int -> int>

fun mult 0 y = 0

| mult n y = y + (mult (n-1) y);

fun mult' 0 = <fn y => 0>

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

Note type of result <int ->

int>

5Cse583 Winterl 2002

Unfold mult’ by hand(mult’ 2) =

<fn y => y + ~(mult’ 1) y> =

<fn y => y + ~(<fn z => z + ~(mult’ 0) z>) y> =

<fn y => y + ~(<fn z => z + ~(<fn x => 0>) z>) y> = Note the alpha renaming of y,z,x

<fn y => y + ~(<fn z => z + (fn x => 0) z>) y> Using the bracket escape cancel law

<fn y => y + (fn z => z + (fn x => 0) z) y>

Why is it then, that when I type mult’ 2 into MetaML I get the following?

-| mult' 2;

val it = <(fn a => a %+ a %+ 0)> : <int -> int>

6Cse583 Winterl 2002

Safe beta at work!

-| feature 1;

Safe-beta is off.

val it = false : bool

-| mult' 2 ;

val it =

<(fn a => a %+ ((fn b => b %+ ((fn c => 0)) b)) a)>

: <int -> int>

With safe-beta turned off we get the expected answer.Note how much uglier the expected answer isWhat property makes safe-beta applicable?

7Cse583 Winterl 2002

memberHave: member : 'a list -> 'a -> boolWant: member' : 'a list -> <'a> -> <bool>

fun member [] x = false

| member (y::ys) x =

if x=y then true else member ys x;

fun member' [] x = <false>

| member' (y::ys) x =

<if ~x = y then true

else ~(member' ys x)>;

8Cse583 Winterl 2002

Example: member-| member' [2,3] <9>;

val it =

<if 9 %= %y then true

else if 9 %= %y then true

else false>

: <bool>

Why do we have %y in the result?How can we fix this aesthetic problem? (hint use: lift)

Can we make the last nested if if 9 %= %y then true else false

Be replaced by just (9 %= %y) (hint make a special case for lists of length 1)

9Cse583 Winterl 2002

member’ againfun member' [] x = <false>

| member' [y] x = <~x = ~(lift y)>

| member' (y::ys) x =

<if ~x = ~(lift y)

then true

else ~(member' ys x)>;

-| member' [2,3] <9>;

val it = <if 9 %= 2 then true else 9 %= 3>

: <bool>

10Cse583 Winterl 2002

dotprodHave: dotprod : int -> int list -> int list -> int Want: dotprod’ : int -> int list -> <int list -> int>

fun dotprod 0 xs ys = 0

| dotprod n (x::xs) (y::ys) =

(x * y) + (dotprod (n-1) xs ys)

The function nth will come in handyfun nth 0 (x::xs) = x

| nth n (x::xs) = nth (n-1) xs;

11Cse583 Winterl 2002

Dotprod (continued)

fun help 0 next xs = <fn y => 0>

| help n next (x::xs) =

<fn ys => ( ~(lift x) * (nth ~(lift next) ys) )

+ ~(help (n-1) (next+1) xs) ys>;

fun dotprod' n xs = help n 0 xs;

Example:

-| dotprod' 3 [0,1,2];

val it =

<fn a => (0 %* %nth 0 a) %+ (1 %* %nth 1 a)

%+ (2 %* %nth 2 a) %+ 0)> : <int list -> int>

12Cse583 Winterl 2002

Can we do without nth ?We canfun dotprod' 0 xs = <fn ys => 0> | dotprod' n (x::xs) = <fn (y::ys) => ( ~(lift x) * y ) + ~(dotprod' (n-1) xs) ys>;

But-| dotprod' 3 [0,1,2];val it = <(fn (b::a) => 0 %* b %+ ((fn (d::c) => 1 %* d %+ ((fn (f::e) => 2 %* f %+ 0)) c)) a)> : <int list -> int>

Safe-Beta doesn’t apply!

13Cse583 Winterl 2002

Applying optimizations-| dotprod' 3 [0,1,2];

val it =

<(fn a => (0 %* %nth 0 a) %+

(1 %* %nth 1 a) %+

(2 %* %nth 2 a) %+ 0)>

Rules 1*x = x 0*x = 0 x+0 = x

<fn a => 0 %+

(%nth 1 a) %+

(2 %* %nth 2 a)>

14Cse583 Winterl 2002

StrategyThe rules 1*x = x 0*x = 0

Can be applied by writing staged versions of multiply ( * ) mult : int -> <int> -> <int>

The Rule x+0 = x

Can be applied by writing a special case for lists of length 1. (We’ve seen this one before)

15Cse583 Winterl 2002

Codefun mult 0 x = <0>

| mult 1 x = x

| mult y x = < ~(lift y) * ~x >;

fun help 0 next xs = <fn y => 0>

| help 1 next [x] =

<fn ys => ~(mult x <nth ~(lift next) ys>)>

| help n next (x::xs) =

<fn ys => ~(mult x <nth ~(lift next) ys>) +

~(help (n-1) (next+1) xs) ys>;

fun dotprod' n xs = help n 0 xs;

16Cse583 Winterl 2002

Example-| dotprod' 3 [0,1,2];

val it =

<fn a => 0 %+ (%nth 1 a) %+ 2 %* (%nth 2 a)>

: <int list -> int>

How do we get rid of the last (0 + …) A analysis version of addition ( + ) add : <int> -> <int> -> <int>

fun add <0> x = x

| add n x = < ~n + ~x >;

17Cse583 Winterl 2002

Final version of dotprod’

fun help 0 next xs = <fn y => 0>

| help 1 next [x] =

<fn ys => ~(mult x <nth ~(lift next) ys>)>

| help n next (x::xs) =

<fn ys => ~(add (mult x <nth ~(lift next) ys>)

<~ (help (n-1) (next+1) xs) ys> )>;

fun dotprod' n xs = help n 0 xs;

-| dotprod' 3 [0,1,2];

val it = <fn a => (%nth 1 a) %+ (2 %* %nth 2 a)>

: <int list -> int>

18Cse583 Winterl 2002

3 stage dot-prodfun nth (x::xs) 1 = x | nth (x::xs) n = nth xs (n-1);

(* iprod : int -> Vector -> Vector -> int *)fun iprod n v w = if n '>' 0 then ((nth v n) * (nth w n)) + (iprod (n-1) v w) else 0;

(* iprod2 : int -> <Vector -> <Vector -> int>> *)fun iprod2 n = <fn v => <fn w => ~(~(if n '>' 0 then << (~(lift (nth v n)) * (nth w n)) + (~(~(iprod2 (n-1)) v) w) >> else <<0>>)) >>;

19Cse583 Winterl 2002

Results of staging-| val f1 = iprod2 3; (* Results from stage 1 *)val f1 = <(fn a => <(fn b => ~(%lift (%nth a %n)) %* (%nth b %n) %+ ~(%lift (%nth a %n)) %* (%nth b %n) %+ ~(%lift (%nth a %n)) %* (%nth b %n) %+ 0)>)> : <int list -> <int list -> int>>

-| val f2 = (run f1) [1,0,4]; (* Results stage 2 *)val f2 = <(fn a => (4 %* (%nth a %n)) %+ (0 %* (%nth a %n)) %+ (1 %* (%nth a %n)) %+ 0)> : <int list -> int>

20Cse583 Winterl 2002

Generator vs TransformerThe function iprod2 is written in generator form

iprod2 : int -> <Vector -> <Vector -> int>>

fun iprod2 n = <fn v => <fn w =>

~(~(if n '>' 0

then << (~(lift (nth v n)) * (nth w n)) +

(~(~(iprod2 (n-1)) v) w)

>>

else <<0>>)) >>;

Also possible to write as Transformer p3 : int -> <Vector> -> <<Vector>> -> <<int>>

fun p3 n v w =

if n '>' 0

then << (~(lift (nth ~v n)) * (nth ~ ~w n)) +

~ ~(p3 (n-1) v w) >>

else <<0>>;

21Cse583 Winterl 2002

From 3-level transformer to generator

fun back2 f = <fn x => <fn y => ~ ~(f <x> <<y>>)>>;fun iprod3 n = back2 (p3 n);

val f3 = iprod3 3; (* Results from stage 1 *)<(fn a => <(fn b => ~(%lift (%nth a %n)) %* %nth b %n %+ ~(%lift (%nth a %n)) %* %nth b %n %+ ~(%lift (%nth a %n)) %* %nth b %n %+ 0)>)>

val f4 = (run f3) [1,0,4]; (* Results stage 2 *)<fn a => (4 %* %nth a %n) %+ (0 %* %nth a %n) %+ (1 %* %nth a %n) %+ 0>

22Cse583 Winterl 2002

Optimizing 3-stages

First write staged arithmetic functions

fun add' <0> y = y

| add' x <0> = x

| add' x y = < ~x + ~y >;

fun mult' 0 y = <0>

| mult' 1 y = y

| mult' x y = <~(lift x) * ~y>;

23Cse583 Winterl 2002

Next use them in 3 level code

fun p4 n v w =

if n '>' 0

then <add' < ~(mult' (nth ~v n)

<(nth ~ ~w n)>) >

~(p4 (n-1) v w) >

else <<0>>;

fun iprod4 n = back2 (p4 n);

24Cse583 Winterl 2002

Resultsval f1 = iprod4 3; (* Results from stage 1 *)-| val f1 =

<(fn a =>

<(fn b =>

~(%add' (<~%mult' (%nth a %n) (<%nth b %n>)>)

(%add' (<~%mult' (%nth a %n) (<%nth b %n>)>)

(%add' (<~%mult' (%nth a %n) (<%nth b %n>)>)

(<0>)))))>)>

val f2 = (run f1) [1,0,4]; (* Results stage 2 *)

-| val f2 =

<fn a => 4 %* (%nth a %n) %+ (%nth a %n)>

Note the calls to add’ and mult’ are escaped to run when the first

generator generates the second generator.

25Cse583 Winterl 2002

3 stage dot-prodfun nth (x::xs) 1 = x | nth (x::xs) n = nth xs (n-1);

(* iprod : int -> Vector -> Vector -> int *)fun iprod n v w = if n '>' 0 then ((nth v n) * (nth w n)) + (iprod (n-1) v w) else 0;

(* iprod2 : int -> <Vector -> <Vector -> int>> *)fun iprod2 n = <fn v => <fn w => ~(~(if n '>' 0 then << (~(lift (nth v n)) * (nth w n)) + (~(~(iprod2 (n-1)) v) w) >> else <<0>>)) >>;

26Cse583 Winterl 2002

Results of staging-| val f1 = iprod2 3; (* Results from stage 1 *)val f1 = <(fn a => <(fn b => ~(%lift (%nth a %n)) %* (%nth b %n) %+ ~(%lift (%nth a %n)) %* (%nth b %n) %+ ~(%lift (%nth a %n)) %* (%nth b %n) %+ 0)>)> : <int list -> <int list -> int>>

-| val f2 = (run f1) [1,0,4]; (* Results stage 2 *)val f2 = <(fn a => (4 %* (%nth a %n)) %+ (0 %* (%nth a %n)) %+ (1 %* (%nth a %n)) %+ 0)> : <int list -> int>

27Cse583 Winterl 2002

Generator vs TransformerThe function iprod2 is written in generator form

iprod2 : int -> <Vector -> <Vector -> int>>

fun iprod2 n = <fn v => <fn w =>

~(~(if n '>' 0

then << (~(lift (nth v n)) * (nth w n)) +

(~(~(iprod2 (n-1)) v) w)

>>

else <<0>>)) >>;

Also possible to write as Transformer p3 : int -> <Vector> -> <<Vector>> -> <<int>>

fun p3 n v w =

if n '>' 0

then << (~(lift (nth ~v n)) * (nth ~ ~w n)) +

~ ~(p3 (n-1) v w) >>

else <<0>>;

28Cse583 Winterl 2002

From 3-level transformer to generator

fun back2 f = <fn x => <fn y => ~ ~(f <x> <<y>>)>>;fun iprod3 n = back2 (p3 n);

val f3 = iprod3 3; (* Results from stage 1 *)<(fn a => <(fn b => ~(%lift (%nth a %n)) %* %nth b %n %+ ~(%lift (%nth a %n)) %* %nth b %n %+ ~(%lift (%nth a %n)) %* %nth b %n %+ 0)>)>

val f4 = (run f3) [1,0,4]; (* Results stage 2 *)<fn a => (4 %* %nth a %n) %+ (0 %* %nth a %n) %+ (1 %* %nth a %n) %+ 0>

29Cse583 Winterl 2002

Optimizing 3-stages(* add : int -> int -> <Vector> -> <int> *)

fun add i x y e =

if x=0

then e

else if x=1

then <(nth ~y ~(lift i)) + ~e>

else <(~(lift x) * (nth ~y ~(lift i))) + ~e>;

(* p3 : int -> <Vector> -> <<Vector>> -> <<int>> *)

fun p3 n v w =

if n = 1

then << ~(add n (nth ~v n) ~w <0>) >>

else << ~(add n (nth ~v n) ~w

< ~ ~(p3 (n-1) v w) >) >>;

30Cse583 Winterl 2002

Resultsfun iprod3 n = back2 (p3 n);

val f3 = iprod3 3;

val f4 = (run f3) [1,0,4];

val f4 =

<(fn a => 4 %* %nth a 3 %+ %nth a 1 %+ 0)>

: <int list -> int>

31Cse583 Winterl 2002

Review Using lift where appropriateThe use of helper functionsTransformers vs generatorsSpecial case for static lists of length 1Staged versions of binary operators where one of the arguments is static, often allow special “rules” to be appliedWhen will the “safe” object level equations like safe-beta, safe-eta, and let-lifting apply?