View
220
Download
0
Category
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?
Recommended