(* print_string is just a pre-defined function (not a keyword or anything) *) let x = print_string "Hello, World!\n" (* underscore is not a variable *) let _ = print_string "Hello, World!\n" let h = "Hello, " let w = "World!\n" let _ = print_string (h ^ w) let f x = print_string (h ^ w) (* function application is juxtaposition -- get used to it *) (* f is polymorphic -- degenerately because it ignores x *) let y1 = f 37 let y2 = f f let y3 = y1 (* Every expression has one type -- we've seen int, string, unit, t1 -> t2 and type variables 'a *) (* an explicit type can help with debugging or to artificially constrain *) let g (x : int) = f x let _ = g 37 (*let _ = g "hi mom"*) (* A really small infinite loop -- do not worry about the inferred type *) (* rec is necesary -- else forever is unbound (would refer to earlier one) *) let rec forever x = forever x (* A more useful recursive function, incorrect for negative x *) (* Note precedence requires parentheses here *) let rec fact x = if x == 0 then 1 else x * (fact (x - 1)) (* parentheses necessary here too -- see currying below *) (* ^ is string concatenation *) let _ = print_string ((string_of_int (fact 6)) ^ "\n") (* everything is an expression *) let fact2 x = (if x == 0 then 1 else x * fact (x - 1)) * 2 / 2 (* local variables and functions look very similar to top-level ones *) (* indentation is just style *) let quadruple x = let double y = y + y in let ans = double x + double x in ans (* functions can be anonymous *) let quadruple2 x = (fun x -> x + x) x + (fun x -> x + x) x (* In fact, we've been using a shortcut: "let f x = e" is really just "let f = fun x -> e" *) let quadruple3 x = let double = fun x -> x + x in double x + double x let _ = print_string ((string_of_int (quadruple 7)) ^ "\n") let _ = print_string ((string_of_int (quadruple2 7)) ^ "\n") let _ = print_string ((string_of_int (quadruple3 7)) ^ "\n") (* Higher-order programming is great for reuse *) (* The boring way... *) let print_int_and_newline i = print_string ((string_of_int i) ^ "\n") let _ = print_int_and_newline (quadruple 7); print_int_and_newline (quadruple2 7); print_int_and_newline (quadruple3 7) (* With passing functions... (and our first 2-argument function) *) (* and useful polymorphism -- though we're not using it *) let print_int_and_newline2 i f = print_int_and_newline (f i) let _ = print_int_and_newline2 7 quadruple; print_int_and_newline2 7 quadruple2; print_int_and_newline2 7 quadruple3 (* inferior style... *) let print_on_seven1 f = print_int_and_newline2 7 f (* The camlers delight -- partial application *) let print_on_seven2 = print_int_and_newline2 7 (* What's really going on: * Every function takes exactly one argument * "Multiple arguments is syntactic sugar" * Application "associates to the left" *) let print_int_and_newline2 = fun f -> (fun i -> print_int_and_newline (f i)) let _ = (print_int_and_newline2 fact) 6 (* closures and static scoping *) let y = 5 let return11 = let x = 6 in fun () -> x + y let y = 7 let x = 8 let _ = print_string "demonstrate closures..." let _ = print_int_and_newline (return11 ()) (* Variables are not mutable *) let x = 9 let f() = x let x = x + 1 let g() = x let _ = print_int_and_newline (f()+g()) (* Refs are mutable, but should be used sparingly. *) let x = ref 9 let f () = !x let _ = x := !x + 1 let g () = !x let _ = print_int_and_newline (f()+g()) (************************ Aggregate Types ******************************) (* records -- definition, creation, projection *) type int_pair = {first : int; second : int} let sum_int_pr x = x.first + x.second let pr1 = {first = 3; second = 4} let _ = sum_int_pr pr1 + sum_int_pr {first=5;second=6} (* all record labels must be distinct (namespaces make this a bit less annoying) the reason is type inference -- see sum_int_pair polymorphic type constructurs *) type 'a pair = {a_first : 'a; a_second : 'a} let sum_pr f x = f x.a_first + f x.a_second let pr2 = {a_first = 3; a_second = 4} let _ = sum_pr (fun x->x) pr2 + sum_pr (fun x->x) {a_first=5;a_second=6} let pr3 = {a_first = "hi"; a_second = "mom"} let pr4 = {a_first = pr2; a_second = pr2} let sum_int = sum_pr (fun x -> x) let sum_str = sum_pr String.length let sum_int_pair = sum_pr sum_int let _ = print_int_and_newline (sum_int pr2) let _ = print_int_and_newline (sum_str pr3) let _ = print_int_and_newline (sum_int_pair pr4) (* discriminated unions also known as "datatypes" -- definition, creation, projection *) type food = Foo of int | Bar of int_pair | Baz of int * int | Quux let foo3 = Foo (1 + 2) let bar12 = Bar pr1 let baz1_120 = Baz(1,fact 5) let quux = Quux (* not much point in this one *) let is_a_foo x = match x with Foo i -> true | Bar pr -> false | Baz(i,j) -> false | Quux -> false let sum_food x = match x with Foo i -> i | Bar pr -> sum_int_pr pr | Baz(i,j) -> i + j | Quux -> 0 (* Note: variant names must be capitalized, other identifiers must not be. *) (* booleans and if are built-in funny syntax (uncapitalized) *) let print_bool1 b = print_string (if b then "true\n" else "false\n") let print_bool2 b = print_string (match b with true -> "true\n" | false -> "false\n") let _ = print_bool1 true; print_bool2 false (* recursive types *) type int_tree = Leaf | Node of int * int_tree * int_tree type 'a lst = Null | Cons of 'a * 'a lst let lst1 = Cons(3,Null) let lst2 = Cons(1,Cons(2,lst1)) (* let lst_bad = Cons("hi",lst2) *) let lst3 = Cons("hi",Cons("mom",Null)) let lst4 = Cons (Cons (3,Null), Cons (Cons (4,Null), Null)) let rec len l = match l with Null -> 0 | Cons(x,rest) -> 1 + len rest let rec sum l = match l with Null -> 0 | Cons(x,rest) -> x + sum rest let rec append lst1 lst2 = match lst1 with Null -> lst2 | Cons(x,rest) -> Cons(x,append rest lst2) let nest = Cons (Cons (3,Null), Cons (Cons (4,Null), Null)) (* In fact 'a list is built-in and has funny syntax: [] is like Null :: (infix) is like Cons *) let list1 = 3::[] let list2 = 1::2::list1 let list3 = [5;6;7] let rec append2 lst1 lst2 = (* built-in infix @ *) match lst1 with [] -> lst2 | x::rest -> x :: append2 rest lst2 (* tuples -- defining record types all the time is a pain and unnecessary *) let x = (3,"hi",(fun x -> x), fun x -> x ^ "ism") let z = match x with (i,s,f1,f2) -> f1 i (* nasty error message without parens around identity function *) (* also (i,_,f1,_). also let expressions *) let f x y = x + y let f pr = (match pr with (x,y) -> x+y) let f (x,y) = x + y let f (x1,y1) (x2,y2) = x1 + y2 type sign = P | N | Z let multsign x1 x2 = let sign x = if x>=0 then (if x=0 then Z else P) else N in match (sign x1,sign x2) with (P,P) -> P | (N,N) -> P | (Z,_) -> Z | (_,Z) -> Z | _ -> N (* many say bad style! *) exception ZipLengthMismatch let rec zip3 lst1 lst2 lst3 = match (lst1,lst2,lst3) with ([],[],[]) -> [] | (hd1::tl1,hd2::tl2,hd3::tl3) -> (hd1,hd2,hd3)::(zip3 tl1 tl2 tl3) | _ -> raise ZipLengthMismatch (* exceptions *) exception MyException let mydiv x y = if y=0 then raise MyException else x/y let yourdiv x y e = if y=0 then raise e else x/y (* exceptions can carry values too -- see the manual *)