Newer
Older

Dan Grossman
committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#utop_prompt_dummy
let _ = UTop.set_show_box false
(* Local Bindings *)
let silly1 (z : int) =
let x = if z > 0 then z else 34 in
let y = x + 9 in
if x > y then x * 2 else y * y
let silly2 () = (* poor style, just showing let expressions are expressions *)
let x = 1 in
(let x = 2 in x+1) + (let y = x+2 in y+1)
let celsius_of_fahrenheit (tempF : float) =
(tempF -. 32.0) *. 5.0 /. 9.0
(* example where let expressions probably make code more readable even though
no computations are repeated *)
(* will have better ways to do this with variant types *)
let is_first_warmer ((temp1 : float), (is_celsius1 : bool),
(temp2 : float), (is_celsius2 : bool)) =
let temp1C = if is_celsius1 then temp1 else celsius_of_fahrenheit temp1 in
let temp2C = if is_celsius2 then temp2 else celsius_of_fahrenheit temp2 in
temp1C > temp2C
(* example where we avoid repeating a computation, but it would not matter much *)
let rec squaring_sequence ((x:float), (n:int)) =
if n=0 then
[]
else
let sq = x *. x in sq :: squaring_sequence(sq,n-1)
let rec range ((lo : int),(hi : int)) =
if lo < hi then
lo :: range (lo + 1, hi)
else
[]
let nats_upto1 (x : int) =
range (0,x)
let nats_upto2 (x : int) =
let rec range ((lo : int),(hi : int)) =
if lo < hi then
lo :: range (lo + 1,hi)
else
[]
in
range (0,x)
let nats_upto3 (x : int) =
let rec loop (lo : int) = (* loop is NOT a special word, could call it fred *)
if lo < x then
lo :: loop (lo + 1)
else
[]
in
loop 0
(* badly named: evaluates to 0 on empty list *)
let rec bad_max (xs : int list) =
if xs = [] then
0 (* bad semantic style *)
else if List.tl xs = [] then
List.hd xs
else if List.hd xs > bad_max (List.tl xs) then
List.hd xs
else
bad_max (List.tl xs)
let rec better_max (xs : int list) =
if xs = [] then
0 (* bad semantic style *)
else if List.tl xs = [] then
List.hd xs
else
let tl_max = better_max (List.tl xs) in
if List.hd xs > tl_max then
List.hd xs
else
tl_max
let rec good_max1 (xs : int list) =
if xs = [] then
None
else
let tl_ans = good_max1 (List.tl xs) in
if not (tl_ans = None) && Option.get tl_ans > List.hd xs then
tl_ans
else
Some (List.hd xs)
let good_max2 (xs : int list) =
if xs = [] then
None
else
let rec max_nonempty (xs : int list) =
if List.tl xs = [] (* xs better not be [] *) then
List.hd xs
else
let tl_ans = max_nonempty (List.tl xs) in
if List.hd xs > tl_ans then
List.hd xs
else
tl_ans
in
Some (max_nonempty xs)
(*let does_not_typecheck = (good_max1 [3;4;2]) + 4*)
(* A t option is *not* an int *)
let risky_but_works = (Option.get (good_max1 [3;4;2])) + 2
(* type-checks, raises exception *)
(* let risky_and_fails = (Option.get (good_max1 [])) + 2*)
let propagate_option =
let x = good_max1 [3;4;2] in
if Option.is_some x then Some ((Option.get x) + 2) else None
(* benefits of no mutation *)
(* does not matter if returns an alias *)
let sort_pair (pr : int * int) : int * int =
if fst pr < snd pr then
pr (* (fst pr, snd pr) *)
else
(snd pr, fst pr)
(* naturally and efficiently introduces sharing and we don't care *)
let rec append ((xs : 'a list), (ys : 'a list)) =
if xs = [] then
ys
else
List.hd xs :: append (List.tl xs, ys)