(* if expressions vs orelse/andalso *)
val x=10;
val y=5;
if x=10 then true else false;
x=10;
if x=10 then y>2 else y<2;
(x=10 andalso y>2) orelse y<2;
(*
homeworks: should be an sml file, like this.
- use "file.sml";
Be sure to quit & restart sml to get rid of any bindings you have
hanging about.
*)
(* exceptions *)
fun recip10 x = 10 div x
exception DivZero
fun recip10 0 = raise DivZero
| recip10 x = 1 div x
fun invert nil = nil
| invert (x::xs) = (recip10 x)::(invert xs)
handle DivZero => (~1)::(invert xs)
exception RealDivZero of real
fun recip x =
if x < 0.00001
then raise RealDivZero x
else 1.0/x
(* returning functions *)
fun add(x,y) = x+y
fun prefix_mkr pre =
let
fun cat post = pre^post
in
cat
end;
(prefix_mkr "Sir") "Cary";
fun add(x,y) = x+y
val add = (fn (x,y) => x+y);
fun prefix_mkr pre = (fn post => pre ^ post)
(*
val knightify=prefix_mkr "Sir"
=> knightify = (fn post => pre^post, pre="Sir")
(* k1 and k2 are not quite the same *)
fun k1 x = (prefix_mkr "Sir") x
val k2 = prefix_mkr "Sir";
(*
k2 = ((fn post => pre ^ post), closure: pre="Sir")
k1 = (fn ....), closure:
k1 evaluates prefix_mkr every time it's called. prefix_mkr was
evaluated once when k2 was bound, but subsequent evaluations of k2
don't evaluate it any more.
*)
(* functions as data: lists of functions *)
val male=[prefix_mkr "King", prefix_mkr "Duke", prefix_mkr "Sir"];
val female=[prefix_mkr "Queen", prefix_mkr "Duchess", prefix_mkr "Lady"];
fun excess (titles,name) = (hd titles) ((hd(tl(titles)) name));
excess(male,"Matt");
excess(female,"Martha");
fun countup_mkr m =
let fun count i
= if i > m then nil else i::(count (i+1))
in count end;
val max20 = countup_mkr 20;
max20 1;
max20 15;
(* countup_mkr with an anonymous function?
fun countup_mkr m = (fn i => if i > m then nil else i::(??? (i+1)))
curried version:
fun countup_mkr m = (fn i => if i > m
then nil
else i::((countup_mkr m) (i+1)));
*)
fun incr_mkr x = (fn y => x+y)
val incr_mkr = (fn x => (fn y => x+y));
val plus = (fn x => (fn y => x+y));
fun plus2(x,y) = x+y
(* we say: "plus is the curried version of plus2" *)
(* from logicial H.B. Curry; originally by Schonfinkel *)
(*
partial application:
We think of plus as taking two arguments, so that conceptually it's
the same as plus2. But because it's curried, we can "partially
apply" it:
*)
val inc3 = plus 3; (* inc3 is the function that increments by 3 *)
fun incr_mkr x = plus x; (* incr_mkr is really just a partial *)
(* application of x *)
(* Currying is used so much there's easier syntax for it *)
fun plus x y = x+y (* syntatic sugar for val plus = (fn x=>(fn y=>x+y)) *)
(*
A curried version of our prefix function: now prefix_mkr is just a
partial application of prefix
*)
fun prefix pre post = pre ^ post
fun prefix_mkr pre = prefix pre;
(* summation from i=0 to m of f(i) *)
(* summation takes a function as argument *)
fun summation f 0 = f 0
| summation f i = (f i) + (summation f (i-1))
(* tail recursive version *)
fun summation f m =
let fun sum (i,z) =
if i=m
then z
else sum (i+1, z+ (f i))
in
sum(0,0)
end
fun square x = x*x;
summation square 10;
val square = (fn x => x*x);
summation square 10;
summation (fn x=>x*x) 10;
summation (fn x=>x) 10;
fun f(i,j) = i*j
(* sum i=1..m j=1..n f(i,j) *)
val m = 10;
val n = 6;
summation (fn i=>summation (fn j=>f(i,j)) n) m;
(* a curried version of f makes the summation call easier *)
fun h i j = i*j;
summation (fn i=>summation (h i) n) m;
(* common functionals: map, filter *)
fun map f nil = nil
| map f (x::xs) = (f x)::(map f xs);
map recip [0.1,0.2,0.3,1.0,10.0];
(* size "string" = length of the string *)
val nums = ["one","two","three","four"];
map size nums;
fun filter pred nil = nil
| filter pred (x::xs) = if pred x
then x::(filter pred xs)
else filter pred xs
;
filter (fn a => size a = 3) nums;
(*
As map and filter are curried functions, they can be partially
applied too.
*)
fun double x = 2*x;
fun even x = (x mod 2) = 0;
map (map double) [[1],[2,3],[4,5,6]];
map (filter even) [[1],[2,3],[4,5,6]];
(* fold functionals *)
(*
IMPORTANT: these version of fold are from an older version of ML and
are NOT the same as the foldl and foldright used these days. See the
notes to section 4 for the modern ML versions.
foldleft op base [x1...xn] = ((..((base op x1) op x2)..) op xn)
foldrightight op base [x1...xn] = (x1 op (x2 op ... (xn op base) ..))
Another way to think about it: partially applying an xi to op gives
a function that operates on things of base's type. foldleft is that
function when base is applied on the left; foldright has base applied on
the right.
*)
fun foldleft f b nil = b
| foldleft f b (x::xs) = foldleft f (f(b,x)) xs
fun foldright f b nil = b
| foldright f b (x::xs) = f(x, foldright f b xs)
fun countup m =
let fun count i = if i>m
then nil
else i::(count (i+1))
in count 1 end
;
fun plus (a,b) = a+b;
fun minus (a,b) = a-b;
foldright plus 0 (countup 10);
foldright minus 0 (countup 10);
foldleft minus 0 (countup 10);
foldright minus 0 (countup 4);
foldright (op +) 0 (countup 10);
foldright (op -) 0 (countup 10);
foldleft (op * ) 1 (countup 4);
foldleft (fn (tot,str)=>tot+(size str)) 0 nums;
foldright (fn (str,tot)=>tot+(size str)) 0 nums;
(* uncurrying *)
(*
- foldleft (foldleft op+) 0 [[1],[2,3],[4,5,6]];
fails b/c (foldleft op+) is fn : int->int list ->int
and we want it to be fn : (int*int list)->int
*)
foldleft (fn (x,y) => foldleft op+ x y) 0 [[1],[2,3],[4,5,6]];
foldright op:: nil [1,2,3,4,5];
foldleft (fn (l,x)=>x::l) nil [1,2,3,4,5];
val reverse = foldleft (fn (l,x)=>x::l) nil;
fun reverse lst = foldleft (fn (l,x)=>x::l) nil lst;
fun inc (n,x) = n+1;
foldleft inc 0 [1,2,3,4,5,6];
(*
A couple of handy functions: explode and implode
*)
explode "1234567890";
implode (reverse (explode "1234567890"));
fun size str = foldleft inc 0 (explode str);
infix mem;
fun x mem nil = false
| x mem (y::ys) = x=y orelse x mem ys
fun newmem(x,lst) = if x mem lst then lst else x::lst
;
(*
newmem takes ''a * ''a list -> ''a list
so to fold it into an ''a list to produce an ''a list, the
accumulator is on the right and the ''a is on the left:
*)
implode (foldright newmem nil (explode "All good things"));
(*
foldleft is the other way around, we switch the arguments using
anonymous function
*)
implode (foldleft (fn (set,elt)=>newmem(elt,set)) nil (explode "All good things"));