this repo has no description

fix: adapt notebook content for new interactive extension format

Remove # prompt prefixes, toplevel output lines, and trailing ;;
from single-expression code blocks across all Foundations (1-11)
and OxCaml notebooks. Keep ;; as phrase separators between multiple
declarations in the same block.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

+291 -650
+14 -26
site/notebooks/foundations/foundations1.mld
··· 179 179 {1 A first session with OCaml} 180 180 181 181 {@ocaml run-on=load[ 182 - # let pi = 3.14159265358979;; 183 - val pi : float = 3.14159265358979 182 + let pi = 3.14159265358979 184 183 ]} 185 184 186 185 The first line of this simple session is a {e value declaration}. It makes the ··· 189 188 declared identifier. 190 189 191 190 {@ocaml run-on=load[ 192 - # pi *. 1.5 *. 1.5;; 193 - - : float = 7.06858347057702829 191 + pi *. 1.5 *. 1.5 194 192 ]} 195 193 196 194 The second line computes the area of the circle with radius [1.5] using the ··· 201 199 OCaml replies with the computed value (about [7.07]) and its type (again [float]). 202 200 203 201 {@ocaml run-on=load[ 204 - # let area r = pi *. r *. r;; 205 - val area : float -> float = <fun> 202 + let area r = pi *. r *. r 206 203 ]} 207 204 208 205 To work abstractly, we should provide the service “compute the area of a ··· 213 210 has type [float -> float]. 214 211 215 212 {@ocaml run-on=load[ 216 - # area 2.0;; 217 - - : float = 12.56637061435916 213 + area 2.0 218 214 ]} 219 215 220 216 The fourth line calls the function [area] supplying [2.0] as the argument. A ··· 229 225 {1 Raising a Number to a Power} 230 226 231 227 {@ocaml run-on=load[ 232 - # let rec npower x n = 228 + let rec npower x n = 233 229 if n = 0 then 1.0 234 - else x *. npower x (n - 1);; 235 - val npower : float -> int -> float = <fun> 230 + else x *. npower x (n - 1) 236 231 ]} 237 232 238 233 Our new [npower] definition can now take additional arguments, reflected in the arrows ··· 273 268 OCaml will notice and ascribe different meaning to each type of constant. 274 269 275 270 {@ocaml run-on=load[ 276 - # let square x = x *. x;; 277 - val square : float -> float = <fun> 271 + let square x = x *. x 278 272 ]} 279 273 280 274 Now for a tiresome but necessary aside. In most languages, the types of ··· 288 282 in the function. 289 283 290 284 {@ocaml run-on=load[ 291 - # let square (x : float) = x *. x;; 292 - val square : float -> float = <fun> 285 + let square (x : float) = x *. x 293 286 ]} 294 287 295 288 Or we can constrain the type of the function’s result: 296 289 297 290 {@ocaml run-on=load[ 298 - # let square x : float = x *. x;; 299 - val square : float -> float = <fun> 291 + let square x : float = x *. x 300 292 ]} 301 293 302 294 OCaml treats the equality and comparison test specially. Expressions like [if x = y then] … ··· 325 317 even, for example: 326 318 327 319 {@ocaml run-on=load[ 328 - # let even n = n mod 2 = 0;; 329 - val even : int -> bool = <fun> 320 + let even n = n mod 2 = 0 330 321 ]} 331 322 332 323 {1 {e Efficiently} Raising a Number to a Power} 333 324 334 325 {@ocaml run-on=load[ 335 - # let rec power x n = 326 + let rec power x n = 336 327 if n = 1 then x 337 328 else if even n then 338 329 power (x *. x) (n / 2) 339 330 else 340 - x *. power (x *. x) (n / 2);; 341 - val power : float -> int -> float = <fun> 331 + x *. power (x *. x) (n / 2) 342 332 ]} 343 333 344 334 {e Mathematical Justification} ··· 377 367 to convert between them: 378 368 379 369 {@ocaml run-on=load[ 380 - # int_of_float 3.14159;; 381 - - : int = 3 382 - # float_of_int 3;; 383 - - : float = 3. 370 + int_of_float 3.14159;; 371 + float_of_int 3 384 372 ]} 385 373 386 374 OCaml’s libraries are organised using “modules”, so we may use compound
+14 -24
site/notebooks/foundations/foundations10.mld
··· 1 1 {0 Lecture 10: Queues and Search Strategies} 2 2 3 3 {@ocaml hidden[ 4 - type 'a tree = Lf | Br of 'a * 'a tree * 'a tree;; 4 + type 'a tree = Lf | Br of 'a * 'a tree * 'a tree 5 5 ]} 6 6 7 7 ··· 46 46 {1 Breadth-First Tree Traversal --- Using Append} 47 47 48 48 {@ocaml[ 49 - # let rec nbreadth = function 49 + let rec nbreadth = function 50 50 | [] -> [] 51 51 | Lf :: ts -> nbreadth ts 52 52 | Br (v, t, u) :: ts -> 53 - v :: nbreadth (ts @ [t; u]);; 54 - val nbreadth : 'a tree list -> 'a list = <fun> 53 + v :: nbreadth (ts @ [t; u]) 55 54 ]} 56 55 57 56 Keeps an {e enormous queue} of nodes of search, and is a wasteful use of [append]. ··· 130 129 {1 Efficient Functional Queues: Code} 131 130 132 131 {@ocaml[ 133 - # type 'a queue = 132 + type 'a queue = 134 133 | Q of 'a list * 'a list;; 135 - type 'a queue = Q of 'a list * 'a list 136 - # let norm = function 134 + let norm = function 137 135 | Q ([], tls) -> Q (List.rev tls, []) 138 136 | q -> q;; 139 - val norm : 'a queue -> 'a queue = <fun> 140 - # let qnull = function 137 + let qnull = function 141 138 | Q ([], []) -> true 142 139 | _ -> false;; 143 - val qnull : 'a queue -> bool = <fun> 144 - # let enq (Q (hds, tls)) x = norm (Q (hds, x::tls));; 145 - val enq : 'a queue -> 'a -> 'a queue = <fun> 146 - # exception Empty;; 147 - exception Empty 148 - # let deq = function 140 + let enq (Q (hds, tls)) x = norm (Q (hds, x::tls));; 141 + exception Empty;; 142 + let deq = function 149 143 | Q (x::hds, tls) -> norm (Q (hds, tls)) 150 144 | _ -> raise Empty;; 151 - val deq : 'a queue -> 'a queue = <fun> 152 - # let qempty = Q ([], []);; 153 - val qempty : 'a queue = Q ([], []) 154 - # let qhd = function 145 + let qempty = Q ([], []);; 146 + let qhd = function 155 147 | Q (x::_, _) -> x 156 - | _ -> raise Empty;; 157 - val qhd : 'a queue -> 'a = <fun> 148 + | _ -> raise Empty 158 149 ]} 159 150 160 151 The datatype of queues prevents confusion with other pairs of lists. The empty ··· 183 174 {1 Breadth-First Tree Traversal --- Using Queues} 184 175 185 176 {@ocaml[ 186 - # let rec breadth q = 177 + let rec breadth q = 187 178 if qnull q then [] 188 179 else 189 180 match qhd q with 190 181 | Lf -> breadth (deq q) 191 - | Br (v, t, u) -> v :: breadth (enq (enq (deq q) t) u);; 192 - val breadth : 'a tree queue -> 'a list = <fun> 182 + | Br (v, t, u) -> v :: breadth (enq (enq (deq q) t) u) 193 183 ]} 194 184 195 185 This function implements the same algorithm as [nbreadth] but uses a different
+33 -70
site/notebooks/foundations/foundations11.mld
··· 79 79 {1 Trying Out References} 80 80 81 81 {@ocaml[ 82 - # let p = ref 5 (* create a reference *);; 83 - val p : int ref = {contents = 5} 84 - # p := !p + 1 (* p now holds value 6 *);; 85 - - : unit = () 86 - # let ps = [ ref 77; p ];; 87 - val ps : int ref list = [{contents = 77}; {contents = 6}] 88 - # List.hd ps := 3;; 89 - - : unit = () 90 - # ps;; 91 - - : int ref list = [{contents = 3}; {contents = 6}] 82 + let p = ref 5 (* create a reference *);; 83 + p := !p + 1 (* p now holds value 6 *);; 84 + let ps = [ ref 77; p ];; 85 + List.hd ps := 3;; 86 + ps 92 87 ]} 93 88 94 89 The first line declares [p] to hold a reference to an integer, ··· 146 141 {1 Iteration: the [while] command} 147 142 148 143 {@ocaml[ 149 - # let tlopt = function 144 + let tlopt = function 150 145 | [] -> None 151 146 | _::xs -> Some xs;; 152 - val tlopt : 'a list -> 'a list option = <fun> 153 - # let length xs = 147 + let length xs = 154 148 let lp = ref xs in (* list of uncounted elements *) 155 149 let np = ref 0 in (* accumulated count *) 156 150 let fin = ref false in ··· 161 155 lp := xs; 162 156 np := 1 + !np 163 157 done; 164 - !np (* the final count is returned *);; 165 - val length : 'a list -> int = <fun> 158 + !np (* the final count is returned *) 166 159 ]} 167 160 168 161 Once we can change the state, we need to do so repeatedly. Recursion can ··· 197 190 {1 Private, Persistent References} 198 191 199 192 {@ocaml[ 200 - # exception TooMuch of int;; 201 - exception TooMuch of int 202 - # let makeAccount initBalance = 193 + exception TooMuch of int;; 194 + let makeAccount initBalance = 203 195 let balance = ref initBalance in 204 196 let withdraw amt = 205 197 if amt > !balance then ··· 209 201 !balance 210 202 end 211 203 in 212 - withdraw;; 213 - val makeAccount : int -> int -> int = <fun> 204 + withdraw 214 205 ]} 215 206 216 207 As you may have noticed, OCaml’s programming style looks clumsy compared with ··· 238 229 {1 Two Bank Accounts} 239 230 240 231 {@ocaml[ 241 - # let student = makeAccount 500;; 242 - val student : int -> int = <fun> 243 - # let director = makeAccount 4000000;; 244 - val director : int -> int = <fun> 245 - # student 5 (* coach fare *);; 246 - - : int = 495 247 - # director 150000 (* Tesla *);; 248 - - : int = 3850000 249 - # student 500 (* oh oh *);; 250 - Exception: TooMuch 5. 251 - Called from Topeval.load_lambda in file "toplevel/byte/topeval.ml", line 89, characters 4-14 232 + let student = makeAccount 500;; 233 + let director = makeAccount 4000000;; 234 + student 5 (* coach fare *);; 235 + director 150000 (* Tesla *);; 236 + student 500 (* oh oh *) 252 237 ]} 253 238 254 239 Each call to [makeAccount] returns a copy of [withdraw] holding ··· 270 255 {1 OCaml Primitives for Arrays} 271 256 272 257 {@ocaml[ 273 - # [|"a"; "b"; "c"|] (* allocate a fresh string array *);; 274 - - : string array = [|"a"; "b"; "c"|] 275 - # Array.make 3 'a' (* array[3] with cell containing 'a' *);; 276 - - : char array = [|'a'; 'a'; 'a'|] 277 - # let aa = Array.init 5 (fun i -> i * 10) (* array[5] initialised to (fun i) *);; 278 - val aa : int array = [|0; 10; 20; 30; 40|] 279 - # Array.get aa 3 (* retrieve the 4th cell in the array *);; 280 - - : int = 30 281 - # Array.set aa 3 42 (* set the 4th cell's value to 42 *);; 282 - - : unit = () 258 + [|"a"; "b"; "c"|] (* allocate a fresh string array *);; 259 + Array.make 3 'a' (* array[3] with cell containing 'a' *);; 260 + let aa = Array.init 5 (fun i -> i * 10) (* array[5] initialised to (fun i) *);; 261 + Array.get aa 3 (* retrieve the 4th cell in the array *);; 262 + Array.set aa 3 42 (* set the 4th cell's value to 42 *) 283 263 ]} 284 264 285 265 There are many other array operations in the [Array] module in the OCaml standard 286 266 library. 287 267 288 268 {@ocaml[ 289 - # Array.make;; 290 - - : int -> 'a -> 'a array = <fun> 291 - # Array.init;; 292 - - : int -> (int -> 'a) -> 'a array = <fun> 293 - # Array.get;; 294 - - : 'a array -> int -> 'a = <fun> 295 - # Array.set;; 296 - - : 'a array -> int -> 'a -> unit = <fun> 269 + Array.make;; 270 + Array.init;; 271 + Array.get;; 272 + Array.set 297 273 ]} 298 274 299 275 OCaml arrays are like references that hold several elements instead of one. The ··· 327 303 rejects it. 328 304 329 305 {@ocaml[ 330 - # let ar = Array.init 20 (fun i -> i * i);; 331 - val ar : int array = 332 - [|0; 1; 4; 9; 16; 25; 36; 49; 64; 81; 100; 121; 144; 169; 196; 225; 256; 333 - 289; 324; 361|] 334 - # Array.get ar 2;; 335 - - : int = 4 336 - # Array.get ar 20;; 337 - Exception: Invalid_argument "index out of bounds". 338 - Raised by primitive operation at unknown location 339 - Called from Topeval.load_lambda in file "toplevel/byte/topeval.ml", line 89, characters 4-14 340 - # Array.set ar 2 33; ar;; 341 - - : int array = 342 - [|0; 1; 33; 9; 16; 25; 36; 49; 64; 81; 100; 121; 144; 169; 196; 225; 256; 343 - 289; 324; 361|] 306 + let ar = Array.init 20 (fun i -> i * i);; 307 + Array.get ar 2;; 308 + Array.get ar 20;; 309 + Array.set ar 2 33; ar 344 310 ]} 345 311 346 312 By calling [Array.set], we then modify the element with subscript 2. Note ··· 355 321 array element satisfies it. 356 322 357 323 {@ocaml[ 358 - # Array.exists (fun i -> i > 200) ar;; 359 - - : bool = true 360 - # Array.exists (fun i -> i < 0) ar;; 361 - - : bool = false 324 + Array.exists (fun i -> i > 200) ar;; 325 + Array.exists (fun i -> i < 0) ar 362 326 ]} 363 327 364 328 {1 References: OCaml {e vs} conventional languages} ··· 393 357 an alternative to arrays. 394 358 395 359 {@ocaml[ 396 - # type 'a mlist = 360 + type 'a mlist = 397 361 | Nil 398 - | Cons of 'a * 'a mlist ref;; 399 - type 'a mlist = Nil | Cons of 'a * 'a mlist ref 362 + | Cons of 'a * 'a mlist ref 400 363 ]} 401 364 402 365 It is worth mentioning that OCaml’s references fully suffice for coding the sort of linked data structures
+12 -18
site/notebooks/foundations/foundations2.mld
··· 31 31 {1 Summing the first {e n} integers} 32 32 33 33 {@ocaml run-on=load[ 34 - # let rec nsum n = 34 + let rec nsum n = 35 35 if n = 0 then 36 36 0 37 37 else 38 - n + nsum (n - 1);; 39 - val nsum : int -> int = <fun> 38 + n + nsum (n - 1) 40 39 ]} 41 40 42 41 The function call [nsum n] computes the sum [1 +] … [+ nz] rather naively, hence the ··· 63 62 {1 Iteratively summing the first [n] integers} 64 63 65 64 {@ocaml run-on=load[ 66 - # let rec summing n total = 65 + let rec summing n total = 67 66 if n = 0 then 68 67 total 69 68 else 70 - summing (n - 1) (n + total);; 71 - val summing : int -> int -> int = <fun> 69 + summing (n - 1) (n + total) 72 70 ]} 73 71 74 72 Function [summing] takes an additional argument: a running total. If ··· 119 117 {1 Silly Summing the First {e n} Integers} 120 118 121 119 {@ocaml run-on=load[ 122 - # let rec sillySum n = 120 + let rec sillySum n = 123 121 if n = 0 then 124 122 0 125 123 else 126 - n + (sillySum (n - 1) + sillySum (n - 1)) / 2;; 127 - val sillySum : int -> int = <fun> 124 + n + (sillySum (n - 1) + sillySum (n - 1)) / 2 128 125 ]} 129 126 130 127 The function calls itself {m 2^n } times! Bigger inputs mean higher costs---but ··· 143 140 computed once and used twice: 144 141 145 142 {@ocaml run-on=load[ 146 - # let x = 2.0 in 143 + let x = 2.0 in 147 144 let y = Float.pow x 20.0 in 148 - y *. (x /. y);; 149 - - : float = 2. 145 + y *. (x /. y) 150 146 ]} 151 147 152 148 You can read [let x = e1 in e2] as assigning (or "binding") the name [x] with ··· 341 337 For example, recall our function [nsum]: 342 338 343 339 {@ocaml run-on=load[ 344 - # let rec nsum n = 340 + let rec nsum n = 345 341 if n = 0 then 346 342 0 347 343 else 348 - n + nsum (n - 1);; 349 - val nsum : int -> int = <fun> 344 + n + nsum (n - 1) 350 345 ]} 351 346 352 347 Given {m n+1 }, it performs a constant amount of work (an addition and ··· 360 355 units. 361 356 362 357 {@ocaml run-on=load[ 363 - # let rec nsumsum n = 358 + let rec nsumsum n = 364 359 if n = 0 then 365 360 0 366 361 else 367 - nsum n + nsumsum (n - 1);; 368 - val nsumsum : int -> int = <fun> 362 + nsum n + nsumsum (n - 1) 369 363 ]} 370 364 371 365 We get the recurrence equations {m T(0)=1 } and {m T(n+1) = T(n)+n }. It is easy to
+44 -102
site/notebooks/foundations/foundations3.mld
··· 3 3 {1 Introduction} 4 4 5 5 {@ocaml run-on=load[ 6 - # let x = [3; 5; 9];; 7 - val x : int list = [3; 5; 9] 8 - # let y = [(1, "one"); (2, "two")];; 9 - val y : (int * string) list = [(1, "one"); (2, "two")] 6 + let x = [3; 5; 9];; 7 + let y = [(1, "one"); (2, "two")] 10 8 ]} 11 9 12 10 A {e list} is an ordered series of elements; repetitions are significant. ··· 29 27 possible. 30 28 31 29 {@ocaml run-on=load[ 32 - # x @ [2; 10];; 33 - - : int list = [3; 5; 9; 2; 10] 34 - # List.rev [(1, "one"); (2, "two")];; 35 - - : (int * string) list = [(2, "two"); (1, "one")] 30 + x @ [2; 10];; 31 + List.rev [(1, "one"); (2, "two")] 36 32 ]} 37 33 38 34 The infix operator [@] (also called [List.append]) concatenates two lists. ··· 47 43 }} 48 44 49 45 {@ocaml run-on=load[ 50 - # let nil = [];; 51 - val nil : 'a list = [] 52 - # 1 :: nil;; 53 - - : int list = [1] 54 - # 1 :: 2 :: nil;; 55 - - : int list = [1; 2] 46 + let nil = [];; 47 + 1 :: nil;; 48 + 1 :: 2 :: nil 56 49 ]} 57 50 58 51 The operator [::] (also called [List.cons] for “construct”), puts a new element on ··· 88 81 {1 Getting at the Head and Tail} 89 82 90 83 {@ocaml run-on=load[ 91 - # let null = function 84 + let null = function 92 85 | [] -> true 93 86 | x :: l -> false;; 94 - val null : 'a list -> bool = <fun> 95 - # null [];; 96 - - : bool = true 97 - # null [1; 2; 3];; 98 - - : bool = false 99 - # let hd (x::l) = x;; 100 - Line 1, characters 7-17: 101 - Warning 8 [partial-match]: this pattern-matching is not exhaustive. 102 - Here is an example of a case that is not matched: 103 - [] 104 - val hd : 'a list -> 'a = <fun> 105 - # hd [1; 2; 3];; 106 - - : int = 1 107 - # let tl (x::l) = l;; 108 - Line 1, characters 7-17: 109 - Warning 8 [partial-match]: this pattern-matching is not exhaustive. 110 - Here is an example of a case that is not matched: 111 - [] 112 - val tl : 'a list -> 'a list = <fun> 113 - # tl [7; 6; 5];; 114 - - : int list = [6; 5] 87 + null [];; 88 + null [1; 2; 3];; 89 + let hd (x::l) = x;; 90 + hd [1; 2; 3];; 91 + let tl (x::l) = l;; 92 + tl [7; 6; 5] 115 93 ]} 116 94 117 95 The empty list has neither head nor tail. Applying [hd] or [tl] to [[]] ··· 136 114 types of their arguments and results. Note their types! 137 115 138 116 {@ocaml[ 139 - # null;; 140 - - : 'a list -> bool = <fun> 141 - # hd;; 142 - - : 'a list -> 'a = <fun> 143 - # tl;; 144 - - : 'a list -> 'a list = <fun> 117 + null;; 118 + hd;; 119 + tl 145 120 ]} 146 121 147 122 Symbols ['a] and ['b] are called {e type variables} and stand for any types. Code ··· 153 128 {1 Computing the Length of a List} 154 129 155 130 {@ocaml[ 156 - # let rec nlength = function 131 + let rec nlength = function 157 132 | [] -> 0 158 133 | x :: xs -> 1 + nlength xs;; 159 - val nlength : 'a list -> int = <fun> 160 - # nlength [];; 161 - - : int = 0 162 - # nlength [5; 6; 7];; 163 - - : int = 3 134 + nlength [];; 135 + nlength [5; 6; 7] 164 136 ]} 165 137 166 138 {math ··· 179 151 To understand its role, consider the following faulty code: 180 152 181 153 {@ocaml run-on=load[ 182 - # let rec nlength [] = 0;; 183 - Line 1, characters 16-22: 184 - Warning 8 [partial-match]: this pattern-matching is not exhaustive. 185 - Here is an example of a case that is not matched: 186 - _::_ 187 - val nlength : 'a list -> int = <fun> 188 - # let rec nlength (x::xs) = 1 + nlength xs;; 189 - Line 1, characters 16-40: 190 - Warning 8 [partial-match]: this pattern-matching is not exhaustive. 191 - Here is an example of a case that is not matched: 192 - [] 193 - val nlength : 'a list -> int = <fun> 154 + let rec nlength [] = 0;; 155 + let rec nlength (x::xs) = 1 + nlength xs 194 156 ]} 195 157 196 158 These are two declarations, not one. First we declare [nlength] to be a ··· 211 173 {1 Efficiently Computing the Length of a List} 212 174 213 175 {@ocaml run-on=load[ 214 - # let rec addlen n = function 176 + let rec addlen n = function 215 177 | [] -> n 216 178 | x::xs -> addlen (n + 1) xs;; 217 - val addlen : int -> 'a list -> int = <fun> 218 - # addlen 0 [5; 6; 7];; 219 - - : int = 3 179 + addlen 0 [5; 6; 7] 220 180 ]} 221 181 222 182 Recall that the use of [function] introduces an extra (unnamed) argument ··· 239 199 [addlen], supplying zero as the initial value of {m n }. 240 200 241 201 {@ocaml run-on=load[ 242 - # let length xs = addlen 0 xs;; 243 - val length : 'a list -> int = <fun> 244 - # length [5; 6; 7; 8];; 245 - - : int = 4 202 + let length xs = addlen 0 xs;; 203 + length [5; 6; 7; 8] 246 204 ]} 247 205 248 206 The recursive calls do not nest: this version is iterative. It takes {m O(1) } ··· 252 210 {1 Append: List Concatenation} 253 211 254 212 {@ocaml run-on=load[ 255 - # let rec append xs ys = 213 + let rec append xs ys = 256 214 match xs, ys with 257 215 | [], ys -> ys 258 216 | x::xs, ys -> x :: append xs ys;; 259 - val append : 'a list -> 'a list -> 'a list = <fun> 260 - # append [1; 2; 3] [4];; 261 - - : int list = [1; 2; 3; 4] 262 - # let (@) = append;; 263 - val ( @ ) : 'a list -> 'a list -> 'a list = <fun> 264 - # [1; 2; 3] @ [4];; 265 - - : int list = [1; 2; 3; 4] 217 + append [1; 2; 3] [4];; 218 + let (@) = append;; 219 + [1; 2; 3] @ [4] 266 220 ]} 267 221 268 222 Patterns can be as complicated as we like. Here, the two patterns are ··· 301 255 Let us consider one way to reverse a list. 302 256 303 257 {@ocaml run-on=load[ 304 - # let rec nrev = function 258 + let rec nrev = function 305 259 | [] -> [] 306 - | x::xs -> (nrev xs) @ [x];; 307 - val nrev : 'a list -> 'a list = <fun> 260 + | x::xs -> (nrev xs) @ [x] 308 261 ]} 309 262 310 263 {@ocaml run-on=load[ 311 - # nrev [1; 2; 3];; 312 - - : int list = [3; 2; 1] 264 + nrev [1; 2; 3] 313 265 ]} 314 266 315 267 {math ··· 335 287 {1 Reversing a List in {m O(n) }} 336 288 337 289 {@ocaml run-on=load[ 338 - # let rec rev_app xs ys = 290 + let rec rev_app xs ys = 339 291 match xs, ys with 340 292 | [], ys -> ys 341 - | x::xs, ys -> rev_app xs (x::ys);; 342 - val rev_app : 'a list -> 'a list -> 'a list = <fun> 293 + | x::xs, ys -> rev_app xs (x::ys) 343 294 ]} 344 295 345 296 {math ··· 355 306 prepends them to [ys]. Now we may declare 356 307 357 308 {@ocaml run-on=load[ 358 - # let rev xs = rev_app xs [];; 359 - val rev : 'a list -> 'a list = <fun> 360 - # rev [1; 2; 3];; 361 - - : int list = [3; 2; 1] 309 + let rev xs = rev_app xs [];; 310 + rev [1; 2; 3] 362 311 ]} 363 312 364 313 It is easy to see that this reverse function performs just {m n } conses, given ··· 387 336 program formats its results ultimately as strings. 388 337 389 338 {@ocaml run-on=load[ 390 - # (* a character constant *) 'a';; 391 - - : char = 'a' 392 - # (* a string constant of length 1 *) "a";; 393 - - : string = "a" 394 - # (* a string constant of length 3 *) "abc";; 395 - - : string = "abc" 396 - # String.length "abc";; 397 - - : int = 3 398 - # (* concatenate two strings *) "abc" ^ "def";; 399 - - : string = "abcdef" 339 + (* a character constant *) 'a';; 340 + (* a string constant of length 1 *) "a";; 341 + (* a string constant of length 3 *) "abc";; 342 + String.length "abc";; 343 + (* concatenate two strings *) "abc" ^ "def" 400 344 ]} 401 345 402 346 In a few programming languages, strings simply are lists of characters. In ··· 437 381 Consider the polymorphic types in these two function declarations: 438 382 439 383 {@ocaml[ 440 - # let id x = x;; 441 - val id : 'a -> 'a = <fun> 442 - # let rec loop x = loop x;; 443 - val loop : 'a -> 'b = <fun> 384 + let id x = x;; 385 + let rec loop x = loop x 444 386 ]} 445 387 446 388 Explain why these types make logical sense, preventing run time type errors, even for expressions
+24 -84
site/notebooks/foundations/foundations4.mld
··· 16 16 They can be implemented in OCaml as follows: 17 17 18 18 {@ocaml[ 19 - # let rec take i = function 19 + let rec take i = function 20 20 | [] -> [] 21 21 | x::xs -> 22 22 if i > 0 then x :: take (i - 1) xs 23 23 else [];; 24 - val take : int -> 'a list -> 'a list = <fun> 25 - # let rec drop i = function 24 + let rec drop i = function 26 25 | [] -> [] 27 26 | x::xs -> 28 27 if i > 0 then drop (i-1) xs 29 - else x::xs;; 30 - val drop : int -> 'a list -> 'a list = <fun> 28 + else x::xs 31 29 ]} 32 30 33 31 Applications of [take] and [drop] will appear in future lectures. Typically, ··· 71 69 {1 Equality Tests} 72 70 73 71 {@ocaml[ 74 - # let rec member x = function 72 + let rec member x = function 75 73 | [] -> false 76 74 | y::l -> 77 75 if x = y then true 78 - else member x l;; 79 - val member : 'a -> 'a list -> bool = <fun> 76 + else member x l 80 77 ]} 81 78 82 79 All the list functions we have encountered up to now have been “polymorphic”, ··· 106 103 {1 Building a List of Pairs} 107 104 108 105 {@ocaml[ 109 - # let rec zip xs ys = 106 + let rec zip xs ys = 110 107 match xs, ys with 111 108 | (x::xs, y::ys) -> (x, y) :: zip xs ys 112 - | _ -> [];; 113 - val zip : 'a list -> 'b list -> ('a * 'b) list = <fun> 109 + | _ -> [] 114 110 ]} 115 111 116 112 {math \left.[x_1,\ldots,x_n]\atop ··· 134 130 function to the elements of another list {m [z_1,\ldots,z_n] }. 135 131 136 132 {@ocaml[ 137 - # let rec unzip = function 133 + let rec unzip = function 138 134 | [] -> ([], []) 139 135 | (x, y)::pairs -> 140 136 let xs, ys = unzip pairs in 141 - (x::xs, y::ys);; 142 - val unzip : ('a * 'b) list -> 'a list * 'b list = <fun> 137 + (x::xs, y::ys) 143 138 ]} 144 139 145 140 Given a list of pairs, [unzip] has to build {e two} lists of ··· 160 155 inverts this operation. Their types reflect what they do: 161 156 162 157 {@ocaml[ 163 - # zip;; 164 - - : 'a list -> 'b list -> ('a * 'b) list = <fun> 165 - # unzip;; 166 - - : ('a * 'b) list -> 'a list * 'b list = <fun> 158 + zip;; 159 + unzip 167 160 ]} 168 161 169 162 If the lists are of unequal length, [zip] discards surplus items at the ··· 181 174 but not every local binding can be eliminated as easily. 182 175 183 176 {@ocaml[ 184 - # let conspair ((x, y), (xs, ys)) = (x::xs, y::ys);; 185 - val conspair : ('a * 'b) * ('a list * 'b list) -> 'a list * 'b list = <fun> 186 - # let rec unzip = function 177 + let conspair ((x, y), (xs, ys)) = (x::xs, y::ys);; 178 + let rec unzip = function 187 179 | [] -> ([], []) 188 - | xy :: pairs -> conspair (xy, unzip pairs);; 189 - val unzip : ('a * 'b) list -> 'a list * 'b list = <fun> 180 + | xy :: pairs -> conspair (xy, unzip pairs) 190 181 ]} 191 182 192 183 Making the function iterative yields [revUnzip] below, which is ··· 197 188 iteration. 198 189 199 190 {@ocaml[ 200 - # let rec revUnzip = function 191 + let rec revUnzip = function 201 192 | ([], xs, ys) -> (xs, ys) 202 193 | ((x, y)::pairs, xs, ys) -> 203 - revUnzip (pairs, x::xs, y::ys);; 204 - val revUnzip : ('a * 'b) list * 'a list * 'b list -> 'a list * 'b list = 205 - <fun> 194 + revUnzip (pairs, x::xs, y::ys) 206 195 ]} 207 196 208 197 {1 An Application: Making Change} ··· 218 207 }} 219 208 220 209 {@ocaml[ 221 - # let rec change till amt = 210 + let rec change till amt = 222 211 match till, amt with 223 212 | _, 0 -> [] 224 213 | [], _ -> raise (Failure "no more coins!") 225 214 | c::till, amt -> if amt < c then change till amt 226 - else c :: change (c::till) (amt - c);; 227 - val change : int list -> int -> int list = <fun> 215 + else c :: change (c::till) (amt - c) 228 216 ]} 229 217 230 218 Although nobody considers making change for zero, this is the simplest way to ··· 251 239 and write a new [change] function. 252 240 253 241 {@ocaml[ 254 - # let rec change till amt = 242 + let rec change till amt = 255 243 match till, amt with 256 244 | _ , 0 -> [ [] ] 257 245 | [] , _ -> [] ··· 261 249 | cs :: css -> (c::cs) :: allc css 262 250 in 263 251 allc (change (c::till) (amt - c)) @ 264 - change till amt;; 265 - val change : int list -> int -> int list list = <fun> 252 + change till amt 266 253 ]} 267 254 268 255 Look at the type: the result is now a list of lists. ··· 292 279 {1 All Ways of Making Change --- Faster!} 293 280 294 281 {@ocaml[ 295 - # let rec change till amt chg chgs = 282 + let rec change till amt chg chgs = 296 283 match till, amt with 297 284 | _ , 0 -> chg::chgs 298 285 | [] , _ -> chgs 299 286 | c::till , amt -> if amt < 0 then chgs 300 287 else change (c::till) (amt - c) (c::chg) 301 - (change till amt chg chgs);; 302 - val change : int list -> int -> int list -> int list list -> int list list = 303 - <fun> 288 + (change till amt chg chgs) 304 289 ]} 305 290 306 291 We’ve added {e another} accumulating parameter! Repeatedly improving simple code ··· 342 327 How does this version of [zip] differ from the one above? 343 328 344 329 {@ocaml skip[ 345 - # let rec zip xs ys = 330 + let rec zip xs ys = 346 331 match xs, ys with 347 332 | (x::xs, y::ys) -> (x, y) :: zip xs ys 348 - | ([], []) -> [];; 349 - Lines 2-4, characters 2-20: 350 - Warning 8 [partial-match]: this pattern-matching is not exhaustive. 351 - Here is an example of a case that is not matched: 352 - (x::xs, []) 353 - val zip : 'a list -> 'b list -> ('a * 'b) list = <fun> 354 - ]} 355 - 356 - 357 - 358 - 359 - 360 - 361 - 362 - 363 - 364 - 365 - 366 - 367 - 368 - 369 - 370 - 371 - 372 - 373 - 374 - 375 - 376 - 377 - 378 - 379 - 380 - 381 - 382 - 383 - 384 - 385 - 386 - 387 - 388 - 389 - 390 - Lines 2-4, characters 5-23: 391 - Warning 8 [partial-match]: this pattern-matching is not exhaustive. 392 - Here is an example of a case that is not matched: 393 - (_::_, []) 333 + | ([], []) -> [] 394 334 ]} 395 335 396 336 {2 Exercise 4.4}
+16 -80
site/notebooks/foundations/foundations5.mld
··· 57 57 lines of code. 58 58 59 59 {@ocaml[ 60 - # let nextrandom seed = 60 + let nextrandom seed = 61 61 let a = 16807.0 in 62 62 let m = 2147483647.0 in 63 63 let t = a *. seed in 64 64 t -. m *. (floor (t /. m));; 65 - val nextrandom : float -> float = <fun> 66 - # let rec randlist (seed, seeds) = function 65 + let rec randlist (seed, seeds) = function 67 66 | 0 -> (seed, seeds) 68 - | n -> randlist (nextrandom seed, seed::seeds) (n-1);; 69 - val randlist : float * float list -> int -> float * float list = <fun> 67 + | n -> randlist (nextrandom seed, seed::seeds) (n-1) 70 68 ]} 71 69 72 70 We can now bind the identifier [rs] to a list of 10,000 random numbers. 73 71 74 72 {@ocaml[ 75 - # let seed, rs = randlist (1.0, []) 10000;; 76 - val seed : float = 1043618065. 77 - val rs : float list = 78 - [1484786315.; 925166085.; 1614852353.; 721631166.; 173942219.; 1229443779.; 79 - 789328014.; 570809709.; 1760109362.; 270600523.; 2108528931.; 16480421.; 80 - 519782231.; 162430624.; 372212905.; 1954184989.; 898872741.; 1651521688.; 81 - 1114791388.; 1325968501.; 1469981427.; 465437343.; 1732504088.; 82 - 280054095.; 1924919450.; 1244369648.; 1524535715.; 706293012.; 83 - 1372325856.; 1302473561.; 941382430.; 2137445578.; 1937168414.; 84 - 1852570660.; 495231255.; 1092873378.; 140232191.; 328129841.; 632752255.; 85 - 227857208.; 1616471915.; 719842438.; 1402481130.; 745001020.; 791471334.; 86 - 2131048000.; 312659966.; 1389551813.; 443838892.; 854190041.; 741774068.; 87 - 267473377.; 1372555293.; 1539748349.; 697860888.; 1261546017.; 734770781.; 88 - 1512111397.; 813238415.; 1034499961.; 602256496.; 462191385.; 250718457.; 89 - 246489360.; 295426232.; 468306241.; 877829533.; 1130589227.; 1914364883.; 90 - 1479854970.; 878528585.; 1268712064.; 115837978.; 1803525169.; 689954646.; 91 - 1174020926.; 651968560.; 391152461.; 1776325865.; 2015344107.; 246977673.; 92 - 1381242649.; 1115030853.; 190703911.; 316761032.; 464218769.; 1537522160.; 93 - 1958981931.; 390463588.; 224009597.; 235243732.; 620352731.; 1374109567.; 94 - 832140633.; 675075162.; 1296171190.; 2009054653.; 1534419747.; 145880482.; 95 - 1649432515.; 403989126.; 1112417244.; 1290575192.; 896661113.; 218545469.; 96 - 1002393512.; 2131316096.; 551979127.; 932010335.; 665881436.; 1975412808.; 97 - 639877791.; 1781707137.; 894518191.; 568004958.; 1331430214.; 629489848.; 98 - 183264178.; 162027282.; 464592882.; 93302056.; 1178713033.; 1401486247.; 99 - 1846150129.; 1646978216.; 1104441491.; 111995009.; 66193165.; 2038880392.; 100 - 79340676.; 871801051.; 967550305.; 2067810758.; 1600354198.; 1746626663.; 101 - 1516388116.; 1308870791.; 173082747.; 189881227.; 478010722.; 739707315.; 102 - 255334803.; 164203714.; 1893097038.; 1587694259.; 292950569.; 918323194.; 103 - 41453146.; 1217297445.; 256768724.; 586494122.; 586258194.; 660494391.; 104 - 507554325.; 699716071.; 672895139.; 76065072.; 1594869218.; 1439459639.; 105 - 641123634.; 1650611940.; 177447368.; 301427463.; 525804524.; 553672425.; 106 - 926899509.; 794676486.; 690277940.; 2115070333.; 1062048650.; 1653192448.; 107 - 1808855340.; 126475289.; 1028198214.; 1739565096.; 1515748830.; 108 - 427491435.; 319330584.; 666483848.; 854842154.; 1853528448.; 1975611245.; 109 - 1905343266.; 1229802342.; 1416055428.; 2091603253.; 1068308139.; 110 - 198239748.; 982076370.; 1094563396.; 44402415.; 889814989.; 290736902.; 111 - 417580014.; 1935788352.; 595665917.; 367638848.; 894945148.; 1868608068.; 112 - 317883051.; 941451621.; 1595942893.; 789094274.; 1150772108.; 422742112.; 113 - 1444245279.; 1273601104.; 256005435.; 1742330161.; 1514599036.; 114 - 956344512.; 2113041793.; 293237373.; 1386995194.; 1509339194.; 891946522.; 115 - 1020832915.; 592544922.; 1746311153.; 1471539715.; 143832370.; 116 - 2041568248.; 1039556199.; 1608726047.; 1205124472.; 2123533995.; 117 - 1560620058.; 1837598795.; 1028172251.; 98318742.; 1405510706.; 118 - 1047695837.; 59221314.; 1822176683.; 1096018886.; 1528104537.; 119 - 1270922857.; 812074106.; 291115596.; 795788616.; 638657646.; 2034314619.; 120 - 1527649272.; 156357479.; 1010056202.; 1139413443.; 1110927723.; 121 - 1216083346.; 846825145.; 2100385733.; 315213605.; 1629637749.; 122 - 1139833627.; 895118866.; 296359237.; 1361440746.; 1188627020.; 123 - 1964199872.; 166733080.; 54185744.; 575493576.; 1810324496.; 1765549585.; 124 - 53514233.; 747348448.; 61758907.; 1710119765.; 188311628.; 8827553.; 125 - 67975851.; 1808633248.; 1290488843.; 1264775607.; 1711469075.; 126 - 1537468597.; 706677101.; 518290019.; 190285086.; 157683412.; 985907152.; 127 - 1571668636.; 632570698.; 791081325.; 1773794197.; 1787141077.; 128 - 1727982894.; 794213057.; 633163306.; 682601940.; 1573439414.; 1041956036.; 129 - 1169697582.; 758914445.; 2096291761.; 1502226099.; 1665995955.; 130 - 948048264.; 1596326605.; 1816773893.; ...] 73 + let seed, rs = randlist (1.0, []) 10000 131 74 ]} 132 75 133 76 {1 Insertion Sort} ··· 135 78 An insert operation does {m n/2} comparisons on average. 136 79 137 80 {@ocaml[ 138 - # let rec ins x = function 81 + let rec ins x = function 139 82 | [] -> [x] 140 83 | y::ys -> if x <= y then x :: y :: ys 141 - else y :: ins x ys;; 142 - val ins : 'a -> 'a list -> 'a list = <fun> 84 + else y :: ins x ys 143 85 ]} 144 86 145 87 {e Insertion sort} takes {m O(n^2)} comparisons on average: 146 88 147 89 {@ocaml[ 148 - # let rec insort = function 90 + let rec insort = function 149 91 | [] -> [] 150 - | x::xs -> ins x (insort xs);; 151 - val insort : 'a list -> 'a list = <fun> 92 + | x::xs -> ins x (insort xs) 152 93 ]} 153 94 154 95 Items from the input are copied one at a time to the output. Each new item is ··· 191 132 {1 Quicksort: The Code} 192 133 193 134 {@ocaml[ 194 - # let rec quick = function 135 + let rec quick = function 195 136 | [] -> [] 196 137 | [x] -> [x] 197 138 | a::bs -> ··· 203 144 else 204 145 part l (x::r) xs 205 146 in 206 - part [] [] bs;; 207 - val quick : 'a list -> 'a list = <fun> 147 + part [] [] bs 208 148 ]} 209 149 210 150 Our OCaml quicksort copies the items. It is still pretty fast, and it is much ··· 236 176 {1 Append-Free Quicksort} 237 177 238 178 {@ocaml[ 239 - # let rec quik = function 179 + let rec quik = function 240 180 | ([], sorted) -> sorted 241 181 | ([x], sorted) -> x::sorted 242 182 | a::bs, sorted -> ··· 248 188 else 249 189 part (l, x::r, xs) 250 190 in 251 - part ([], [], bs);; 252 - val quik : 'a list * 'a list -> 'a list = <fun> 191 + part ([], [], bs) 253 192 ]} 254 193 255 194 The list [sorted] accumulates the result in the {e combine} stage of ··· 272 211 Merge joins two sorted lists. 273 212 274 213 {@ocaml[ 275 - # let rec merge = function 214 + let rec merge = function 276 215 | [], ys -> ys 277 216 | xs, [] -> xs 278 217 | x::xs, y::ys -> 279 218 if x <= y then 280 219 x :: merge (xs, y::ys) 281 220 else 282 - y :: merge (x::xs, ys);; 283 - val merge : 'a list * 'a list -> 'a list = <fun> 221 + y :: merge (x::xs, ys) 284 222 ]} 285 223 286 224 Generalises insert to two lists, and does at most {m m+n-1} comparisons. ··· 304 242 {1 Top-down Merge sort} 305 243 306 244 {@ocaml[ 307 - # let rec tmergesort = function 245 + let rec tmergesort = function 308 246 | [] -> [] 309 247 | [x] -> [x] 310 248 | xs -> 311 249 let k = List.length xs / 2 in 312 250 let l = tmergesort (take k xs) in 313 251 let r = tmergesort (drop k xs) in 314 - merge (l, r);; 315 - Line 6, characters 28-32: 316 - Error: Unbound value take 252 + merge (l, r) 317 253 ]} 318 254 319 255 {m O(n\log n)} comparisons in worst case
+38 -72
site/notebooks/foundations/foundations6.mld
··· 202 202 basic ones supplied with the core OCaml language. 203 203 204 204 {@ocaml run-on=load[ 205 - # type vehicle = Bike 205 + type vehicle = Bike 206 206 | Motorbike 207 207 | Car 208 - | Lorry;; 209 - type vehicle = Bike | Motorbike | Car | Lorry 208 + | Lorry 210 209 ]} 211 210 212 211 {ul {- We have declared a {e new type} named [vehicle]. ··· 240 239 {1 Declaring a Function on Vehicles} 241 240 242 241 {@ocaml run-on=load[ 243 - # let wheels = function 242 + let wheels = function 244 243 | Bike -> 2 245 244 | Motorbike -> 2 246 245 | Car -> 4 247 - | Lorry -> 18;; 248 - val wheels : vehicle -> int = <fun> 246 + | Lorry -> 18 249 247 ]} 250 248 251 249 {ul {- Datatype constructors can be used in patterns. ··· 261 259 {1 A Datatype whose Constructors have Arguments} 262 260 263 261 {@ocaml run-on=load[ 264 - # type vehicle = Bike 262 + type vehicle = Bike 265 263 | Motorbike of int 266 264 | Car of bool 267 - | Lorry of int;; 268 - type vehicle = Bike | Motorbike of int | Car of bool | Lorry of int 265 + | Lorry of int 269 266 ]} 270 267 {ul {- Constructors with arguments (like [Lorry]) are {e distinct values}. (So [Car true] is distinct from [Car false]). 271 268 }{- Different kinds of [vehicle] can belong to one list: [[Bike, Car true, Motorbike 450]] ··· 283 280 reference work). 284 281 285 282 {@ocaml run-on=load[ 286 - # type vehicle = Bike 283 + type vehicle = Bike 287 284 | Motorbike of int (* engine size in CCs *) 288 285 | Car of bool (* true if a Reliant Robin *) 289 - | Lorry of int;; 290 - type vehicle = Bike | Motorbike of int | Car of bool | Lorry of int 286 + | Lorry of int 291 287 ]} 292 288 293 289 The list shown on the slide represents a bicycle, a Reliant Robin and a large ··· 303 299 logic: 304 300 305 301 {@ocaml[ 306 - # let wheels = function 302 + let wheels = function 307 303 | Bike -> 2 308 304 | Motorbike _ -> 2 309 305 | Car robin -> if robin then 3 else 4 310 - | Lorry w -> w;; 311 - val wheels : vehicle -> int = <fun> 306 + | Lorry w -> w 312 307 ]} 313 308 314 309 This function consists of four clauses: ··· 358 353 {1 Exceptions in OCaml} 359 354 360 355 {@ocaml[ 361 - # exception Failure;; 362 - exception Failure 363 - # exception NoChange of int;; 364 - exception NoChange of int 365 - # raise Failure;; 366 - Exception: Failure. 367 - Called from Topeval.load_lambda in file "toplevel/byte/topeval.ml", line 89, characters 4-14 356 + exception Failure;; 357 + exception NoChange of int;; 358 + raise Failure 368 359 ]} 369 360 370 361 Each [exception] declaration introduces a distinct sort of exception, which can ··· 379 370 further information: the integer {m n}. 380 371 381 372 {@ocaml[ 382 - # try 373 + try 383 374 print_endline "pre exception"; 384 375 raise (NoChange 1); 385 376 print_endline "post exception"; 386 377 with 387 378 | NoChange _ -> 388 - print_endline "handled a NoChange exception";; 389 - pre exception 390 - handled a NoChange exception 391 - Line 3, characters 4-22: 392 - Warning 21 [nonreturning-statement]: this statement never returns (or has an unsound type.) 393 - - : unit = () 379 + print_endline "handled a NoChange exception" 394 380 ]} 395 381 396 382 The effect of [raise <expr>] is to jump to the most recently-encountered ··· 414 400 alternative to exceptions is to instead return a value of datatype [option]. 415 401 416 402 {@ocaml[ 417 - # let x = Some 1;; 418 - val x : int option = Some 1 403 + let x = Some 1 419 404 ]} 420 405 421 406 [None] signifies an error, while [Some x] returns the solution {m x}. This ··· 427 412 {1 Making Change with Exceptions} 428 413 429 414 {@ocaml[ 430 - # exception Change;; 431 - exception Change 432 - # let rec change till amt = 415 + exception Change;; 416 + let rec change till amt = 433 417 match till, amt with 434 418 | _, 0 -> [] 435 419 | [], _ -> raise Change 436 420 | c::till, amt -> if amt < 0 then raise Change 437 421 else try c :: change (c::till) (amt - c) 438 - with Change -> change till amt;; 439 - val change : int list -> int -> int list = <fun> 422 + with Change -> change till amt 440 423 ]} 441 424 442 425 In the Lists lectures, we considered the problem of making change. The greedy ··· 500 483 {1 Binary Trees, a Recursive Datatype} 501 484 502 485 {@ocaml run-on=load[ 503 - # type 'a tree = 486 + type 'a tree = 504 487 Lf 505 - | Br of 'a * 'a tree * 'a tree;; 506 - type 'a tree = Lf | Br of 'a * 'a tree * 'a tree 488 + | Br of 'a * 'a tree * 'a tree 507 489 ]} 508 490 509 491 {@ocaml run-on=load hidden[ 510 - # let tree_printer to_txt t = 492 + let tree_printer to_txt t = 511 493 let rec tree = function 512 494 | Lf -> TreePrinter.Lf 513 495 | Br (n, l, r) -> TreePrinter.Br (n, [tree l; tree r]) ··· 517 499 | TreePrinter.Br (n, _) -> to_txt n 518 500 in 519 501 let svg = TreePrinter.svg_of_tree TreePrinter.default_params to_txt (tree t) in 520 - Mime_printer.push "image/svg" (Format.asprintf "%a" (Tyxml.Svg.pp ()) svg);; 521 - val tree_printer : 522 - ('a -> string Tyxml.Svg.wrap Tyxml.Svg.wrap) -> 'a tree -> unit = <fun> 502 + Mime_printer.push "image/svg" (Format.asprintf "%a" (Tyxml.Svg.pp ()) svg) 523 503 ]} 524 504 525 505 A data structure with multiple branching is called a “tree”. Trees can 526 506 represent mathematical expressions, logical formulae, computer programs, the 527 507 phrase structure of English sentences, etc. 528 508 529 - {x@ocaml run-on=load[ 530 - # let tree = Br(1, Br(2, Br(4, Lf, Lf), 509 + {@ocaml run-on=load[ 510 + let tree = Br(1, Br(2, Br(4, Lf, Lf), 531 511 Br(5, Lf, Lf)), 532 512 Br(3, Lf, Lf));; 533 - val tree : int tree = 534 - Br (1, Br (2, Br (4, Lf, Lf), Br (5, Lf, Lf)), Br (3, Lf, Lf)) 535 - # tree_printer string_of_int tree;; 536 - - : unit = () 537 - ]x[ 538 - {%html: <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" 539 - "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> 540 - <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="452" height="252"><rect width="100%" height="100%" x="0" y="0" fill="none"></rect><rect width="50px" height="40px" x="200.5" y="0.5" rx="5" fill="#8888ff" stroke="black"></rect><rect width="50px" height="40px" x="120.5" y="70.5" rx="5" fill="#8888ff" stroke="black"></rect><rect width="50px" height="40px" x="40.5" y="140.5" rx="5" fill="#8888ff" stroke="black"></rect><rect width="50px" height="40px" x="0.5" y="210.5" rx="5" fill="#8888ff" stroke="black"></rect><rect width="50px" height="40px" x="80.5" y="210.5" rx="5" fill="#8888ff" stroke="black"></rect><rect width="50px" height="40px" x="200.5" y="140.5" rx="5" fill="#8888ff" stroke="black"></rect><rect width="50px" height="40px" x="160.5" y="210.5" rx="5" fill="#8888ff" stroke="black"></rect><rect width="50px" height="40px" x="240.5" y="210.5" rx="5" fill="#8888ff" stroke="black"></rect><rect width="50px" height="40px" x="360.5" y="70.5" rx="5" fill="#8888ff" stroke="black"></rect><rect width="50px" height="40px" x="320.5" y="140.5" rx="5" fill="#8888ff" stroke="black"></rect><rect width="50px" height="40px" x="400.5" y="140.5" rx="5" fill="#8888ff" stroke="black"></rect><path d="M225 40 C 225 70, 385 40, 385 70" stroke="black" fill="none"></path><path d="M225 40 C 225 70, 145 40, 145 70" stroke="black" fill="none"></path><path d="M145 110 C 145 140, 225 110, 225 140" stroke="black" fill="none"></path><path d="M145 110 C 145 140, 65 110, 65 140" stroke="black" fill="none"></path><path d="M65 180 C 65 210, 105 180, 105 210" stroke="black" fill="none"></path><path d="M65 180 C 65 210, 25 180, 25 210" stroke="black" fill="none"></path><path d="M225 180 C 225 210, 265 180, 265 210" stroke="black" fill="none"></path><path d="M225 180 C 225 210, 185 180, 185 210" stroke="black" fill="none"></path><path d="M385 110 C 385 140, 425 110, 425 140" stroke="black" fill="none"></path><path d="M385 110 C 385 140, 345 110, 345 140" stroke="black" fill="none"></path><text x="225" y="20" text-anchor="middle" font-size="10pt">1</text><text x="145" y="90" text-anchor="middle" font-size="10pt">2</text><text x="65" y="160" text-anchor="middle" font-size="10pt">4</text><text x="25" y="230" text-anchor="middle" font-size="10pt">Lf</text><text x="105" y="230" text-anchor="middle" font-size="10pt">Lf</text><text x="225" y="160" text-anchor="middle" font-size="10pt">5</text><text x="185" y="230" text-anchor="middle" font-size="10pt">Lf</text><text x="265" y="230" text-anchor="middle" font-size="10pt">Lf</text><text x="385" y="90" text-anchor="middle" font-size="10pt">3</text><text x="345" y="160" text-anchor="middle" font-size="10pt">Lf</text><text x="425" y="160" text-anchor="middle" font-size="10pt">Lf</text></svg> %} 513 + tree_printer string_of_int tree 541 514 ]} 542 515 543 516 ··· 548 521 OCaml lists are a datatype and could be declared as follows: 549 522 550 523 {@ocaml run-on=load[ 551 - # type 'a mylist = 524 + type 'a mylist = 552 525 | Nil 553 - | Cons of 'a * 'a mylist;; 554 - type 'a mylist = Nil | Cons of 'a * 'a mylist 526 + | Cons of 'a * 'a mylist 555 527 ]} 556 528 557 529 We could even declare [::] as an infix constructor. The only ··· 564 536 that is recursive but not polymorphic. 565 537 566 538 {@ocaml run-on=load[ 567 - # type shape = 539 + type shape = 568 540 | Null 569 - | Join of shape * shape;; 570 - type shape = Null | Join of shape * shape 541 + | Join of shape * shape 571 542 ]} 572 543 573 544 The datatype ['a option] (mentioned above) is the opposite -- it is ··· 576 547 {1 Basic Properties of Binary Trees} 577 548 578 549 {@ocaml run-on=load[ 579 - # let rec count = function 550 + let rec count = function 580 551 | Lf -> 0 (* number of branch nodes *) 581 552 | Br (v, t1, t2) -> 1 + count t1 + count t2;; 582 - val count : 'a tree -> int = <fun> 583 - # let rec depth = function 553 + let rec depth = function 584 554 | Lf -> 0 (* length of longest path *) 585 - | Br (v, t1, t2) -> 1 + max (depth t1) (depth t2);; 586 - val depth : 'a tree -> int = <fun> 555 + | Br (v, t1, t2) -> 1 + max (depth t1) (depth t2) 587 556 ]} 588 557 589 558 The invariant {m \texttt{count}(t)\le 2^{\texttt{depth}(t)} - 1} holds in the functions above. ··· 593 562 measure of a tree’s size: 594 563 595 564 {@ocaml run-on=load[ 596 - # let rec leaves = function 565 + let rec leaves = function 597 566 | Lf -> 1 598 - | Br (v, t1, t2) -> leaves t1 + leaves t2;; 599 - val leaves : 'a tree -> int = <fun> 567 + | Br (v, t1, t2) -> leaves t1 + leaves t2 600 568 ]} 601 569 602 570 This function is redundant because of a basic fact about trees, which can be ··· 624 592 Using the definition of ['a tree] from before: 625 593 626 594 {@ocaml[ 627 - # type 'a tree = Lf | Br of 'a * 'a tree * 'a tree;; 628 - type 'a tree = Lf | Br of 'a * 'a tree * 'a tree 595 + type 'a tree = Lf | Br of 'a * 'a tree * 'a tree 629 596 ]} 630 597 631 598 Examine the following function declaration. What does [ftree (1, n)] accomplish? 632 599 633 600 {@ocaml[ 634 - # let rec ftree k n = 601 + let rec ftree k n = 635 602 if n = 0 then Lf 636 - else Br (k, ftree (2 * k) (n - 1), ftree (2 * k + 1) (n - 1));; 637 - val ftree : int -> int -> int tree = <fun> 603 + else Br (k, ftree (2 * k) (n - 1), ftree (2 * k + 1) (n - 1)) 638 604 ]} 639 605 640 606 {2 Exercise 6.4}
+22 -38
site/notebooks/foundations/foundations7.mld
··· 31 31 keys do not need a concept of ordering, only equality. 32 32 33 33 {@ocaml[ 34 - # exception Missing 35 - exception Missing 36 - # let rec lookup a = function 34 + exception Missing;; 35 + let rec lookup a = function 37 36 | [] -> raise Missing 38 37 | (x, y) :: pairs -> 39 38 if a = x then y 40 - else lookup a pairs 41 - val lookup : 'a -> ('a * 'b) list -> 'b = <fun> 42 - # let update (l, b, y) = (b, y) :: l 43 - val update : ('a * 'b) list * 'a * 'b -> ('a * 'b) list = <fun> 39 + else lookup a pairs;; 40 + let update (l, b, y) = (b, y) :: l 44 41 ]} 45 42 46 43 To enter a new [(key, value)] pair, simply “cons” it to the list with [update]. ··· 78 75 {1 Lookup: Seeks Left or Right} 79 76 80 77 {@ocaml[ 81 - # exception Missing of string 82 - exception Missing of string 83 - # let rec lookup b = function 78 + exception Missing of string;; 79 + let rec lookup b = function 84 80 | Br ((a, x), t1, t2) -> 85 81 if b < a then 86 82 lookup b t1 ··· 89 85 else 90 86 x 91 87 | Lf -> raise (Missing b) 92 - val lookup : string -> (string * 'a) tree -> 'a = <fun> 93 88 ]} 94 89 95 90 This has guaranteed {m O(\log n)} access time {e if} the tree is balanced! ··· 107 102 {1 Update} 108 103 109 104 {@ocaml[ 110 - # let rec update k v = function 105 + let rec update k v = function 111 106 | Lf -> Br ((k, v), Lf, Lf) 112 107 | Br ((a, x), t1, t2) -> 113 108 if k < a then ··· 116 111 Br ((a, x), t1, update k v t2) 117 112 else (* a = k *) 118 113 Br ((a, v), t1, t2) 119 - val update : 'a -> 'b -> ('a * 'b) tree -> ('a * 'b) tree = <fun> 120 114 ]} 121 115 122 116 This is also {m O(\log n)} as it copies the path only, and {e not whole subtrees!} ··· 146 140 {1 Aside: Traversing Trees (3 Methods)} 147 141 148 142 {@ocaml[ 149 - # let rec preorder = function 143 + let rec preorder = function 150 144 | Lf -> [] 151 145 | Br (v, t1, t2) -> 152 - [v] @ preorder t1 @ preorder t2 153 - val preorder : 'a tree -> 'a list = <fun> 154 - # let rec inorder = function 146 + [v] @ preorder t1 @ preorder t2;; 147 + let rec inorder = function 155 148 | Lf -> [] 156 149 | Br (v, t1, t2) -> 157 - inorder t1 @ [v] @ inorder t2 158 - val inorder : 'a tree -> 'a list = <fun> 159 - # let rec postorder = function 150 + inorder t1 @ [v] @ inorder t2;; 151 + let rec postorder = function 160 152 | Lf -> [] 161 153 | Br (v, t1, t2) -> 162 154 postorder t1 @ postorder t2 @ [v] 163 - val postorder : 'a tree -> 'a list = <fun> 164 155 ]} 165 156 166 157 {e Tree traversal} means examining each node of a tree in some order. {{: https://en.wikipedia.org/wiki/The_Art_of_Computer_Programming} D. E. ··· 191 182 eliminated from [quicksort] in the Sorting lecture. 192 183 193 184 {@ocaml[ 194 - # let rec preord = function 185 + let rec preord = function 195 186 | Lf, vs -> vs 196 187 | Br (v, t1, t2), vs -> 197 - v :: preord (t1, preord (t2, vs)) 198 - val preord : 'a tree * 'a list -> 'a list = <fun> 199 - # let rec inord = function 188 + v :: preord (t1, preord (t2, vs));; 189 + let rec inord = function 200 190 | Lf, vs -> vs 201 191 | Br (v, t1, t2), vs -> 202 - inord (t1, v::inord (t2, vs)) 203 - val inord : 'a tree * 'a list -> 'a list = <fun> 204 - # let rec postord = function 192 + inord (t1, v::inord (t2, vs));; 193 + let rec postord = function 205 194 | Lf, vs -> vs 206 195 | Br (v, t1, t2), vs -> 207 196 postord (t1, postord (t2, v::vs)) 208 - val postord : 'a tree * 'a list -> 'a list = <fun> 209 197 ]} 210 198 211 199 One can prove equations relating each of these functions to its counterpart on ··· 280 268 {1 The Lookup Function} 281 269 282 270 {@ocaml[ 283 - # exception Subscript 284 - let rec sub = function 271 + exception Subscript;; 272 + let rec sub = function 285 273 | Lf, _ -> raise Subscript (* Not found *) 286 274 | Br (v, t1, t2), k -> 287 275 if k = 1 then v 288 276 else if k mod 2 = 0 then 289 277 sub (t1, k / 2) 290 278 else 291 - sub (t2, k / 2) 292 - exception Subscript 293 - val sub : 'a tree * int -> 'a = <fun> 294 - # let rec sub = function (* Alternative implementation *) 279 + sub (t2, k / 2);; 280 + let rec sub = function (* Alternative implementation *) 295 281 | Lf, _ -> raise Subscript 296 282 | Br (v, t1, t2), 1 -> v 297 283 | Br (v, t1, t2), k when k mod 2 = 0 -> sub (t1, k / 2) 298 284 | Br (v, t1, t2), k -> sub (t2, k / 2) 299 - val sub : 'a tree * int -> 'a = <fun> 300 285 ]} 301 286 302 287 Notice that we have used a new keyword [when] above, which changes ··· 334 319 {1 The Update Function} 335 320 336 321 {@ocaml[ 337 - # let rec update = function 322 + let rec update = function 338 323 | Lf, k, w -> 339 324 if k = 1 then 340 325 Br (w, Lf, Lf) ··· 347 332 Br (v, update (t1, k / 2, w), t2) 348 333 else 349 334 Br (v, t1, update (t2, k / 2, w)) 350 - val update : 'a tree * int * 'a -> 'a tree = <fun> 351 335 ]} 352 336 353 337 The [update] function also divides the subscript repeatedly by two. When it
+36 -65
site/notebooks/foundations/foundations8.mld
··· 8 8 }} 9 9 10 10 {@ocaml[ 11 - # [(fun n -> n * 2); 11 + [(fun n -> n * 2); 12 12 (fun n -> n * 3); 13 - (fun n -> n + 1)];; 14 - - : (int -> int) list = [<fun>; <fun>; <fun>] 13 + (fun n -> n + 1)] 15 14 ]} 16 15 17 16 Progress in programming languages can be measured by what abstractions they ··· 47 46 The function [fun n -> n*2] is a {e doubling function}. 48 47 49 48 {@ocaml[ 50 - # fun n -> n * 2;; 51 - - : int -> int = <fun> 49 + fun n -> n * 2 52 50 ]} 53 51 54 52 The main purpose of [fun]-notation is to package up small expressions that are to be ··· 57 55 [double], declared as follows: 58 56 59 57 {@ocaml[ 60 - # let double n = n * 2;; 61 - val double : int -> int = <fun> 58 + let double n = n * 2 62 59 ]} 63 60 64 61 The [fun] notation can also do pattern matching, and the [function] keyword ··· 66 63 are all equivalent, with the latter definitions bound to the [is_zero] value and the earlier ones anonymous: 67 64 68 65 {@ocaml[ 69 - # fun x -> match x with 0 -> true | _ -> false;; 70 - - : int -> bool = <fun> 66 + fun x -> match x with 0 -> true | _ -> false 71 67 ]} 72 68 73 69 {1 Curried Functions} ··· 76 72 the string concetenation operator [(^)] to illustrate how this works. 77 73 78 74 {@ocaml[ 79 - # (^);; 80 - - : string -> string -> string = <fun> 75 + (^) 81 76 ]} 82 77 83 78 A short form for the definition of [prefix] is simply to pass multiple ··· 85 80 are equivalent in OCaml: 86 81 87 82 {@ocaml[ 88 - # let prefix = fun a -> fun b -> a ^ b;; 89 - val prefix : string -> string -> string = <fun> 83 + let prefix = fun a -> fun b -> a ^ b 90 84 ]} 91 85 92 86 Currying is the technique of expressing a function taking multiple arguments as nested functions, each taking a single argument. ··· 98 92 Currying is an alternative, where we {e nest} the [fun]-notation: 99 93 100 94 {@ocaml[ 101 - # fun k -> fun n -> n * 2 + k;; 102 - - : int -> int -> int = <fun> 95 + fun k -> fun n -> n * 2 + k 103 96 ]} 104 97 105 98 Applying this curried function to the argument 1 yields another function, in which [k] has been replaced by 1: 106 99 107 100 {@ocaml[ 108 - # let fn = fun k -> fun n -> n * 2 + k;; 109 - val fn : int -> int -> int = <fun> 101 + let fn = fun k -> fun n -> n * 2 + k 110 102 ]} 111 103 112 104 And this function, when applied to 3, yields the result 7. The two arguments are supplied one after another. ··· 123 115 This curried function syntax is nicer than nested [fun] binders: 124 116 125 117 {@ocaml[ 126 - # let prefix a b = a ^ b;; 127 - val prefix : string -> string -> string = <fun> 118 + let prefix a b = a ^ b 128 119 ]} 129 120 130 121 Curried functions allows {e partial application} (to the first argument). ··· 154 145 expressions: 155 146 156 147 {@ocaml[ 157 - # List.hd [dub; promote] "Hamilton";; 158 - Line 1, characters 9-12: 159 - Error: Unbound value dub 148 + List.hd [dub; promote] "Hamilton" 160 149 ]} 161 150 162 151 Here [List.hd] is applied to a list of functions, and the resulting function ··· 167 156 {1 Partial Application: A Curried Insertion Sort} 168 157 169 158 {@ocaml[ 170 - # let insort lessequal = 159 + let insort lessequal = 171 160 let rec ins x = function 172 161 | [] -> [x] 173 162 | y::ys -> if lessequal x y then x :: y :: ys ··· 177 166 | [] -> [] 178 167 | x::xs -> ins x (sort xs) 179 168 in 180 - sort;; 181 - val insort : ('a -> 'a -> bool) -> 'a list -> 'a list = <fun> 169 + sort 182 170 ]} 183 171 184 172 The sorting functions we discussed in earlier lectures are coded to sort floating-point ··· 193 181 Some examples of its use: 194 182 195 183 {@ocaml[ 196 - # insort (<=) [5; 3; 9; 8];; 197 - - : int list = [3; 5; 8; 9] 184 + insort (<=) [5; 3; 9; 8] 198 185 ]} 199 186 200 187 An obscure point: the syntax [(<=)] denotes the comparison operator as a ··· 205 192 {1 map: the “Apply to All” Function} 206 193 207 194 {@ocaml[ 208 - # let rec map f = function 195 + let rec map f = function 209 196 | [] -> [] 210 - | x::xs -> (f x) :: map f xs;; 211 - val map : ('a -> 'b) -> 'a list -> 'b list = <fun> 197 + | x::xs -> (f x) :: map f xs 212 198 ]} 213 199 214 200 The functional [map] applies a function to every element of a list, ··· 219 205 would require a preliminary function declaration: 220 206 221 207 {@ocaml[ 222 - # let rec sillylist = function 208 + let rec sillylist = function 223 209 | [] -> [] 224 - | s::ss -> (s ^ "ppy") :: sillylist ss;; 225 - val sillylist : string list -> string list = <fun> 210 + | s::ss -> (s ^ "ppy") :: sillylist ss 226 211 ]} 227 212 228 213 An expression containing several applications of functionals---such as our ··· 250 235 } 251 236 252 237 {@ocaml[ 253 - # let rec transp = function 238 + let rec transp = function 254 239 | []::_ -> [] 255 240 | rows -> (map List.hd rows) :: 256 - (transp (map List.tl rows));; 257 - val transp : 'a list list -> 'a list list = <fun> 241 + (transp (map List.tl rows)) 258 242 ]} 259 243 260 244 A matrix can be viewed as a list of rows, each row a list of matrix elements. ··· 356 340 {e Dot product} of two vectors---a {e curried function} 357 341 358 342 {@ocaml[ 359 - # let rec dotprod xs ys = 343 + let rec dotprod xs ys = 360 344 match xs, ys with 361 345 | [], [] -> 0.0 362 - | x::xs, y::ys -> (x *. y) +. (dotprod xs ys);; 363 - Lines 2-4, characters 4-50: 364 - Warning 8 [partial-match]: this pattern-matching is not exhaustive. 365 - Here is an example of a case that is not matched: 366 - ([], _::_) 367 - val dotprod : float list -> float list -> float = <fun> 346 + | x::xs, y::ys -> (x *. y) +. (dotprod xs ys) 368 347 ]} 369 348 370 349 {e Matrix product} 371 350 372 351 {@ocaml[ 373 - # let rec matprod arows brows = 352 + let rec matprod arows brows = 374 353 let cols = transp brows in 375 - map (fun row -> map (dotprod row) cols) arows;; 376 - val matprod : float list list -> float list list -> float list list = <fun> 354 + map (fun row -> map (dotprod row) cols) arows 377 355 ]} 378 356 379 357 The [transp brows] converts {m B} into a list of columns, yielding a ··· 396 374 {1 List Functionals for Predicates} 397 375 398 376 {@ocaml[ 399 - # let rec exists p = function 377 + let rec exists p = function 400 378 | [] -> false 401 - | x::xs -> (p x) || (exists p xs);; 402 - val exists : ('a -> bool) -> 'a list -> bool = <fun> 379 + | x::xs -> (p x) || (exists p xs) 403 380 ]} 404 381 405 382 A {e predicate} is a {e boolean-valued} function. ··· 413 390 predicate. If it finds a counterexample then it, too, stops searching. 414 391 415 392 {@ocaml[ 416 - # let rec all p = function 393 + let rec all p = function 417 394 | [] -> true 418 - | x::xs -> (p x) && all p xs;; 419 - val all : ('a -> bool) -> 'a list -> bool = <fun> 395 + | x::xs -> (p x) && all p xs 420 396 ]} 421 397 422 398 The [filter] functional, like [map], transforms lists. It applies a ··· 427 403 {1 Applications of the Predicate Functionals} 428 404 429 405 {@ocaml[ 430 - # let member y xs = 431 - exists (fun x -> x=y) xs;; 432 - val member : 'a -> 'a list -> bool = <fun> 406 + let member y xs = 407 + exists (fun x -> x=y) xs 433 408 ]} 434 409 435 410 {e Testing whether two lists have no common elements} 436 411 437 412 {@ocaml[ 438 - # let disjoint xs ys = 439 - all (fun x -> all (fun y -> x<>y) ys) xs;; 440 - val disjoint : 'a list -> 'a list -> bool = <fun> 413 + let disjoint xs ys = 414 + all (fun x -> all (fun y -> x<>y) ys) xs 441 415 ]} 442 416 443 417 The Lists lecture presented the function [member], which tests whether a ··· 473 447 What does the following function do, and what are its uses? 474 448 475 449 {@ocaml[ 476 - # let sw f x y = f y x;; 477 - val sw : ('a -> 'b -> 'c) -> 'b -> 'a -> 'c = <fun> 450 + let sw f x y = f y x 478 451 ]} 479 452 480 453 {2 Exercise 8.2} ··· 498 471 for type ['a option]. 499 472 500 473 {@ocaml[ 501 - # type 'a option = None | Some of 'a;; 502 - type 'a option = None | Some of 'a 474 + type 'a option = None | Some of 'a 503 475 ]} 504 476 505 477 {2 Exercise 8.5} ··· 507 479 Recall the making change function of Lecture 4: 508 480 509 481 {@ocaml[ 510 - # let rec change till amt = 482 + let rec change till amt = 511 483 match till, amt with 512 484 | _ , 0 -> [ [] ] 513 485 | [] , _ -> [] ··· 517 489 | cs :: css -> (c::cs) :: allc css 518 490 in 519 491 allc (change (c::till) (amt - c)) @ 520 - change till amt;; 521 - val change : int list -> int -> int list list = <fun> 492 + change till amt 522 493 ]} 523 494 524 495 Function [allc] applies the function ‘cons a [c]’ to every element of a list. Eliminate it by
+23 -56
site/notebooks/foundations/foundations9.mld
··· 76 76 }} 77 77 78 78 {@ocaml[ 79 - # type 'a seq = 79 + type 'a seq = 80 80 | Nil 81 81 | Cons of 'a * (unit -> 'a seq);; 82 - type 'a seq = Nil | Cons of 'a * (unit -> 'a seq) 83 - # let head (Cons (x, _)) = x;; 84 - Line 1, characters 9-26: 85 - Warning 8 [partial-match]: this pattern-matching is not exhaustive. 86 - Here is an example of a case that is not matched: 87 - Nil 88 - val head : 'a seq -> 'a = <fun> 89 - # let tail (Cons (_, xf)) = xf ();; 90 - Line 1, characters 9-31: 91 - Warning 8 [partial-match]: this pattern-matching is not exhaustive. 92 - Here is an example of a case that is not matched: 93 - Nil 94 - val tail : 'a seq -> 'a seq = <fun> 82 + let head (Cons (x, _)) = x;; 83 + let tail (Cons (_, xf)) = xf () 95 84 ]} 96 85 97 86 {m \tt Cons(x, xf)} has {e head} {m x} and {e tail function} {m xf} ··· 119 108 {1 The Infinite Sequence: {m k}, {m k+1}, {m k+2}, …} 120 109 121 110 {@ocaml[ 122 - # let rec from k = Cons (k, fun () -> from (k+1));; 123 - val from : int -> int seq = <fun> 124 - # let it = from 1;; 125 - val it : int seq = Cons (1, <fun>) 126 - # let it = tail it;; 127 - val it : int seq = Cons (2, <fun>) 128 - # let it = tail it;; 129 - val it : int seq = Cons (3, <fun>) 111 + let rec from k = Cons (k, fun () -> from (k+1));; 112 + let it = from 1;; 113 + let it = tail it;; 114 + let it = tail it 130 115 ]} 131 116 132 117 Function [from] constructs the infinite sequence of integers starting ··· 142 127 {1 Consuming a Sequence} 143 128 144 129 {@ocaml[ 145 - # let rec get n s = 130 + let rec get n s = 146 131 match n, s with 147 132 | 0, _ -> [] 148 133 | n, Nil -> [] 149 - | n, Cons (x, xf) -> x :: get (n-1) (xf ());; 150 - val get : int -> 'a seq -> 'a list = <fun> 134 + | n, Cons (x, xf) -> x :: get (n-1) (xf ()) 151 135 ]} 152 136 153 137 The above code gets the first {m n} elements as a list. ··· 191 175 {1 Joining Two Sequences} 192 176 193 177 {@ocaml[ 194 - # let rec appendq xq yq = 178 + let rec appendq xq yq = 195 179 match xq with 196 180 | Nil -> yq 197 - | Cons (x, xf) -> Cons(x, fun () -> appendq (xf ()) yq);; 198 - val appendq : 'a seq -> 'a seq -> 'a seq = <fun> 181 + | Cons (x, xf) -> Cons(x, fun () -> appendq (xf ()) yq) 199 182 ]} 200 183 201 184 A more fair alternative: 202 185 203 186 {@ocaml[ 204 - # let rec interleave xq yq = 187 + let rec interleave xq yq = 205 188 match xq with 206 189 | Nil -> yq 207 - | Cons (x, xf) -> Cons (x, fun () -> interleave yq (xf ()));; 208 - val interleave : 'a seq -> 'a seq -> 'a seq = <fun> 190 + | Cons (x, xf) -> Cons (x, fun () -> interleave yq (xf ())) 209 191 ]} 210 192 211 193 Most list functions and functionals have analogues on sequences, but strange ··· 233 215 Filtering lazy lists: 234 216 235 217 {@ocaml[ 236 - # let rec filterq p = function 218 + let rec filterq p = function 237 219 | Nil -> Nil 238 220 | Cons (x, xf) -> 239 221 if p x then 240 222 Cons (x, fun () -> filterq p (xf ())) 241 223 else 242 - filterq p (xf ());; 243 - val filterq : ('a -> bool) -> 'a seq -> 'a seq = <fun> 224 + filterq p (xf ()) 244 225 ]} 245 226 246 227 The infinite sequence {m x}, {m f(x)}, {m f(f(x))}, … 247 228 248 229 {@ocaml[ 249 - # let rec iterates f x = 250 - Cons (x, fun () -> iterates f (f x));; 251 - val iterates : ('a -> 'a) -> 'a -> 'a seq = <fun> 230 + let rec iterates f x = 231 + Cons (x, fun () -> iterates f (f x)) 252 232 ]} 253 233 254 234 The functional [filterq] demands elements of [xq] until it finds ··· 263 243 {1 Numerical Computations on Infinite Sequences} 264 244 265 245 {@ocaml[ 266 - # let next a x = (a /. x +. x) /. 2.0;; 267 - val next : float -> float -> float = <fun> 246 + let next a x = (a /. x +. x) /. 2.0 268 247 ]} 269 248 270 249 Close enough? 271 250 272 251 {@ocaml[ 273 - # let rec within eps = function 252 + let rec within eps = function 274 253 | Cons (x, xf) -> 275 254 match xf () with 276 255 | Cons (y, yf) -> 277 256 if abs_float (x -. y) <= eps then y 278 - else within eps (Cons (y, yf));; 279 - Lines 3-6, characters 6-40: 280 - Warning 8 [partial-match]: this pattern-matching is not exhaustive. 281 - Here is an example of a case that is not matched: 282 - Nil 283 - 284 - Lines 1-6, characters 21-40: 285 - Warning 8 [partial-match]: this pattern-matching is not exhaustive. 286 - Here is an example of a case that is not matched: 287 - Nil 288 - val within : float -> float seq -> float = <fun> 257 + else within eps (Cons (y, yf)) 289 258 ]} 290 259 291 260 Square Roots: 292 261 293 262 {@ocaml[ 294 - # let root a = within 1e6 (iterates (next a) 1.0);; 295 - val root : float -> float = <fun> 263 + let root a = within 1e6 (iterates (next a) 1.0) 296 264 ]} 297 265 298 266 The {e Newton-Raphson method} is widely used for computing square roots. ··· 328 296 it be generalised to concatenate a sequence of sequences? What can go wrong? 329 297 330 298 {@ocaml[ 331 - # let rec concat = function 299 + let rec concat = function 332 300 | [] -> [] 333 - | l::ls -> l @ concat ls;; 334 - val concat : 'a list list -> 'a list = <fun> 301 + | l::ls -> l @ concat ls 335 302 ]} 336 303 337 304 {2 Exercise 9.3}
+15 -15
site/notebooks/oxcaml/local.mld
··· 6 6 let f () = 7 7 let u @ local = [6; 2; 8] in (* mode *) 8 8 let len = Base.List.length u in 9 - len;; 9 + len 10 10 ]} 11 11 12 12 {@ocaml[ 13 13 let f () = 14 14 let local_ u = [6; 2; 8] in 15 15 let len = Base.List.length u in 16 - len;; 16 + len 17 17 ]} 18 18 19 19 {@ocaml[ 20 20 let f () = 21 21 let u : int list @@ local = stack_ [6; 2; 8] in (* modality *) 22 22 let len = Base.List.length u in 23 - len;; 23 + len 24 24 ]} 25 25 26 26 {@ocaml[ 27 27 let f () = 28 28 let u = local_ [6; 2; 8] in 29 29 let len = Base.List.length u in 30 - len;; 30 + len 31 31 ]} 32 32 33 33 Other keywords to spot: [stack_], [global_], [@ global], [exclave_] and [[@local_opt]] ··· 53 53 let foo = 54 54 let local_ bar = ("region", "scope") in 55 55 bar in 56 - fst foo;; 56 + fst foo 57 57 ]} 58 58 59 59 {1 What does [local] mean?} ··· 86 86 {1 Hands-on} 87 87 88 88 {@ocaml[ 89 - # let monday () = let str = "mon" ^ "day" in str;; 89 + let monday () = let str = "mon" ^ "day" in str 90 90 ]} 91 91 92 92 {@ocaml[ 93 - # let bye () = let ciao = "sorry" in failwith ciao;; 93 + let bye () = let ciao = "sorry" in failwith ciao 94 94 ]} 95 95 96 96 {@ocaml[ 97 - # let make_counter () = 97 + let make_counter () = 98 98 let counter = ref (-1) in 99 - fun () -> incr counter; !counter;; 99 + fun () -> incr counter; !counter 100 100 ]} 101 101 102 102 {@ocaml[ 103 - # let state = ref "";; 104 - # let set () = state := "disco";; 103 + let state = ref "";; 104 + let set () = state := "disco" 105 105 ]} 106 106 107 107 {@ocaml[ 108 - # let rec map f = function [] -> [] | x :: u -> f x :: map f u;; 108 + let rec map f = function [] -> [] | x :: u -> f x :: map f u 109 109 ]} 110 110 111 111 {@ocaml[ 112 - # let f1 (local_ u : int list) = [1; 2; 3];; 112 + let f1 (local_ u : int list) = [1; 2; 3] 113 113 ]} 114 114 115 115 {@ocaml[ 116 - # let f2 (local_ u : int list) = u;; 116 + let f2 (local_ u : int list) = u 117 117 ]} 118 118 119 119 {@ocaml[ 120 - # let f3 (local_ u : int list) = 42 :: u;; 120 + let f3 (local_ u : int list) = 42 :: u 121 121 ]} 122 122