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 {1 A first session with OCaml} 180 181 {@ocaml run-on=load[ 182 - # let pi = 3.14159265358979;; 183 - val pi : float = 3.14159265358979 184 ]} 185 186 The first line of this simple session is a {e value declaration}. It makes the ··· 189 declared identifier. 190 191 {@ocaml run-on=load[ 192 - # pi *. 1.5 *. 1.5;; 193 - - : float = 7.06858347057702829 194 ]} 195 196 The second line computes the area of the circle with radius [1.5] using the ··· 201 OCaml replies with the computed value (about [7.07]) and its type (again [float]). 202 203 {@ocaml run-on=load[ 204 - # let area r = pi *. r *. r;; 205 - val area : float -> float = <fun> 206 ]} 207 208 To work abstractly, we should provide the service “compute the area of a ··· 213 has type [float -> float]. 214 215 {@ocaml run-on=load[ 216 - # area 2.0;; 217 - - : float = 12.56637061435916 218 ]} 219 220 The fourth line calls the function [area] supplying [2.0] as the argument. A ··· 229 {1 Raising a Number to a Power} 230 231 {@ocaml run-on=load[ 232 - # let rec npower x n = 233 if n = 0 then 1.0 234 - else x *. npower x (n - 1);; 235 - val npower : float -> int -> float = <fun> 236 ]} 237 238 Our new [npower] definition can now take additional arguments, reflected in the arrows ··· 273 OCaml will notice and ascribe different meaning to each type of constant. 274 275 {@ocaml run-on=load[ 276 - # let square x = x *. x;; 277 - val square : float -> float = <fun> 278 ]} 279 280 Now for a tiresome but necessary aside. In most languages, the types of ··· 288 in the function. 289 290 {@ocaml run-on=load[ 291 - # let square (x : float) = x *. x;; 292 - val square : float -> float = <fun> 293 ]} 294 295 Or we can constrain the type of the function’s result: 296 297 {@ocaml run-on=load[ 298 - # let square x : float = x *. x;; 299 - val square : float -> float = <fun> 300 ]} 301 302 OCaml treats the equality and comparison test specially. Expressions like [if x = y then] … ··· 325 even, for example: 326 327 {@ocaml run-on=load[ 328 - # let even n = n mod 2 = 0;; 329 - val even : int -> bool = <fun> 330 ]} 331 332 {1 {e Efficiently} Raising a Number to a Power} 333 334 {@ocaml run-on=load[ 335 - # let rec power x n = 336 if n = 1 then x 337 else if even n then 338 power (x *. x) (n / 2) 339 else 340 - x *. power (x *. x) (n / 2);; 341 - val power : float -> int -> float = <fun> 342 ]} 343 344 {e Mathematical Justification} ··· 377 to convert between them: 378 379 {@ocaml run-on=load[ 380 - # int_of_float 3.14159;; 381 - - : int = 3 382 - # float_of_int 3;; 383 - - : float = 3. 384 ]} 385 386 OCaml’s libraries are organised using “modules”, so we may use compound
··· 179 {1 A first session with OCaml} 180 181 {@ocaml run-on=load[ 182 + let pi = 3.14159265358979 183 ]} 184 185 The first line of this simple session is a {e value declaration}. It makes the ··· 188 declared identifier. 189 190 {@ocaml run-on=load[ 191 + pi *. 1.5 *. 1.5 192 ]} 193 194 The second line computes the area of the circle with radius [1.5] using the ··· 199 OCaml replies with the computed value (about [7.07]) and its type (again [float]). 200 201 {@ocaml run-on=load[ 202 + let area r = pi *. r *. r 203 ]} 204 205 To work abstractly, we should provide the service “compute the area of a ··· 210 has type [float -> float]. 211 212 {@ocaml run-on=load[ 213 + area 2.0 214 ]} 215 216 The fourth line calls the function [area] supplying [2.0] as the argument. A ··· 225 {1 Raising a Number to a Power} 226 227 {@ocaml run-on=load[ 228 + let rec npower x n = 229 if n = 0 then 1.0 230 + else x *. npower x (n - 1) 231 ]} 232 233 Our new [npower] definition can now take additional arguments, reflected in the arrows ··· 268 OCaml will notice and ascribe different meaning to each type of constant. 269 270 {@ocaml run-on=load[ 271 + let square x = x *. x 272 ]} 273 274 Now for a tiresome but necessary aside. In most languages, the types of ··· 282 in the function. 283 284 {@ocaml run-on=load[ 285 + let square (x : float) = x *. x 286 ]} 287 288 Or we can constrain the type of the function’s result: 289 290 {@ocaml run-on=load[ 291 + let square x : float = x *. x 292 ]} 293 294 OCaml treats the equality and comparison test specially. Expressions like [if x = y then] … ··· 317 even, for example: 318 319 {@ocaml run-on=load[ 320 + let even n = n mod 2 = 0 321 ]} 322 323 {1 {e Efficiently} Raising a Number to a Power} 324 325 {@ocaml run-on=load[ 326 + let rec power x n = 327 if n = 1 then x 328 else if even n then 329 power (x *. x) (n / 2) 330 else 331 + x *. power (x *. x) (n / 2) 332 ]} 333 334 {e Mathematical Justification} ··· 367 to convert between them: 368 369 {@ocaml run-on=load[ 370 + int_of_float 3.14159;; 371 + float_of_int 3 372 ]} 373 374 OCaml’s libraries are organised using “modules”, so we may use compound
+14 -24
site/notebooks/foundations/foundations10.mld
··· 1 {0 Lecture 10: Queues and Search Strategies} 2 3 {@ocaml hidden[ 4 - type 'a tree = Lf | Br of 'a * 'a tree * 'a tree;; 5 ]} 6 7 ··· 46 {1 Breadth-First Tree Traversal --- Using Append} 47 48 {@ocaml[ 49 - # let rec nbreadth = function 50 | [] -> [] 51 | Lf :: ts -> nbreadth ts 52 | Br (v, t, u) :: ts -> 53 - v :: nbreadth (ts @ [t; u]);; 54 - val nbreadth : 'a tree list -> 'a list = <fun> 55 ]} 56 57 Keeps an {e enormous queue} of nodes of search, and is a wasteful use of [append]. ··· 130 {1 Efficient Functional Queues: Code} 131 132 {@ocaml[ 133 - # type 'a queue = 134 | Q of 'a list * 'a list;; 135 - type 'a queue = Q of 'a list * 'a list 136 - # let norm = function 137 | Q ([], tls) -> Q (List.rev tls, []) 138 | q -> q;; 139 - val norm : 'a queue -> 'a queue = <fun> 140 - # let qnull = function 141 | Q ([], []) -> true 142 | _ -> 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 149 | Q (x::hds, tls) -> norm (Q (hds, tls)) 150 | _ -> raise Empty;; 151 - val deq : 'a queue -> 'a queue = <fun> 152 - # let qempty = Q ([], []);; 153 - val qempty : 'a queue = Q ([], []) 154 - # let qhd = function 155 | Q (x::_, _) -> x 156 - | _ -> raise Empty;; 157 - val qhd : 'a queue -> 'a = <fun> 158 ]} 159 160 The datatype of queues prevents confusion with other pairs of lists. The empty ··· 183 {1 Breadth-First Tree Traversal --- Using Queues} 184 185 {@ocaml[ 186 - # let rec breadth q = 187 if qnull q then [] 188 else 189 match qhd q with 190 | 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> 193 ]} 194 195 This function implements the same algorithm as [nbreadth] but uses a different
··· 1 {0 Lecture 10: Queues and Search Strategies} 2 3 {@ocaml hidden[ 4 + type 'a tree = Lf | Br of 'a * 'a tree * 'a tree 5 ]} 6 7 ··· 46 {1 Breadth-First Tree Traversal --- Using Append} 47 48 {@ocaml[ 49 + let rec nbreadth = function 50 | [] -> [] 51 | Lf :: ts -> nbreadth ts 52 | Br (v, t, u) :: ts -> 53 + v :: nbreadth (ts @ [t; u]) 54 ]} 55 56 Keeps an {e enormous queue} of nodes of search, and is a wasteful use of [append]. ··· 129 {1 Efficient Functional Queues: Code} 130 131 {@ocaml[ 132 + type 'a queue = 133 | Q of 'a list * 'a list;; 134 + let norm = function 135 | Q ([], tls) -> Q (List.rev tls, []) 136 | q -> q;; 137 + let qnull = function 138 | Q ([], []) -> true 139 | _ -> false;; 140 + let enq (Q (hds, tls)) x = norm (Q (hds, x::tls));; 141 + exception Empty;; 142 + let deq = function 143 | Q (x::hds, tls) -> norm (Q (hds, tls)) 144 | _ -> raise Empty;; 145 + let qempty = Q ([], []);; 146 + let qhd = function 147 | Q (x::_, _) -> x 148 + | _ -> raise Empty 149 ]} 150 151 The datatype of queues prevents confusion with other pairs of lists. The empty ··· 174 {1 Breadth-First Tree Traversal --- Using Queues} 175 176 {@ocaml[ 177 + let rec breadth q = 178 if qnull q then [] 179 else 180 match qhd q with 181 | Lf -> breadth (deq q) 182 + | Br (v, t, u) -> v :: breadth (enq (enq (deq q) t) u) 183 ]} 184 185 This function implements the same algorithm as [nbreadth] but uses a different
+33 -70
site/notebooks/foundations/foundations11.mld
··· 79 {1 Trying Out References} 80 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}] 92 ]} 93 94 The first line declares [p] to hold a reference to an integer, ··· 146 {1 Iteration: the [while] command} 147 148 {@ocaml[ 149 - # let tlopt = function 150 | [] -> None 151 | _::xs -> Some xs;; 152 - val tlopt : 'a list -> 'a list option = <fun> 153 - # let length xs = 154 let lp = ref xs in (* list of uncounted elements *) 155 let np = ref 0 in (* accumulated count *) 156 let fin = ref false in ··· 161 lp := xs; 162 np := 1 + !np 163 done; 164 - !np (* the final count is returned *);; 165 - val length : 'a list -> int = <fun> 166 ]} 167 168 Once we can change the state, we need to do so repeatedly. Recursion can ··· 197 {1 Private, Persistent References} 198 199 {@ocaml[ 200 - # exception TooMuch of int;; 201 - exception TooMuch of int 202 - # let makeAccount initBalance = 203 let balance = ref initBalance in 204 let withdraw amt = 205 if amt > !balance then ··· 209 !balance 210 end 211 in 212 - withdraw;; 213 - val makeAccount : int -> int -> int = <fun> 214 ]} 215 216 As you may have noticed, OCaml’s programming style looks clumsy compared with ··· 238 {1 Two Bank Accounts} 239 240 {@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 252 ]} 253 254 Each call to [makeAccount] returns a copy of [withdraw] holding ··· 270 {1 OCaml Primitives for Arrays} 271 272 {@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 = () 283 ]} 284 285 There are many other array operations in the [Array] module in the OCaml standard 286 library. 287 288 {@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> 297 ]} 298 299 OCaml arrays are like references that hold several elements instead of one. The ··· 327 rejects it. 328 329 {@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|] 344 ]} 345 346 By calling [Array.set], we then modify the element with subscript 2. Note ··· 355 array element satisfies it. 356 357 {@ocaml[ 358 - # Array.exists (fun i -> i > 200) ar;; 359 - - : bool = true 360 - # Array.exists (fun i -> i < 0) ar;; 361 - - : bool = false 362 ]} 363 364 {1 References: OCaml {e vs} conventional languages} ··· 393 an alternative to arrays. 394 395 {@ocaml[ 396 - # type 'a mlist = 397 | Nil 398 - | Cons of 'a * 'a mlist ref;; 399 - type 'a mlist = Nil | Cons of 'a * 'a mlist ref 400 ]} 401 402 It is worth mentioning that OCaml’s references fully suffice for coding the sort of linked data structures
··· 79 {1 Trying Out References} 80 81 {@ocaml[ 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 87 ]} 88 89 The first line declares [p] to hold a reference to an integer, ··· 141 {1 Iteration: the [while] command} 142 143 {@ocaml[ 144 + let tlopt = function 145 | [] -> None 146 | _::xs -> Some xs;; 147 + let length xs = 148 let lp = ref xs in (* list of uncounted elements *) 149 let np = ref 0 in (* accumulated count *) 150 let fin = ref false in ··· 155 lp := xs; 156 np := 1 + !np 157 done; 158 + !np (* the final count is returned *) 159 ]} 160 161 Once we can change the state, we need to do so repeatedly. Recursion can ··· 190 {1 Private, Persistent References} 191 192 {@ocaml[ 193 + exception TooMuch of int;; 194 + let makeAccount initBalance = 195 let balance = ref initBalance in 196 let withdraw amt = 197 if amt > !balance then ··· 201 !balance 202 end 203 in 204 + withdraw 205 ]} 206 207 As you may have noticed, OCaml’s programming style looks clumsy compared with ··· 229 {1 Two Bank Accounts} 230 231 {@ocaml[ 232 + let student = makeAccount 500;; 233 + let director = makeAccount 4000000;; 234 + student 5 (* coach fare *);; 235 + director 150000 (* Tesla *);; 236 + student 500 (* oh oh *) 237 ]} 238 239 Each call to [makeAccount] returns a copy of [withdraw] holding ··· 255 {1 OCaml Primitives for Arrays} 256 257 {@ocaml[ 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 *) 263 ]} 264 265 There are many other array operations in the [Array] module in the OCaml standard 266 library. 267 268 {@ocaml[ 269 + Array.make;; 270 + Array.init;; 271 + Array.get;; 272 + Array.set 273 ]} 274 275 OCaml arrays are like references that hold several elements instead of one. The ··· 303 rejects it. 304 305 {@ocaml[ 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 310 ]} 311 312 By calling [Array.set], we then modify the element with subscript 2. Note ··· 321 array element satisfies it. 322 323 {@ocaml[ 324 + Array.exists (fun i -> i > 200) ar;; 325 + Array.exists (fun i -> i < 0) ar 326 ]} 327 328 {1 References: OCaml {e vs} conventional languages} ··· 357 an alternative to arrays. 358 359 {@ocaml[ 360 + type 'a mlist = 361 | Nil 362 + | Cons of 'a * 'a mlist ref 363 ]} 364 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 {1 Summing the first {e n} integers} 32 33 {@ocaml run-on=load[ 34 - # let rec nsum n = 35 if n = 0 then 36 0 37 else 38 - n + nsum (n - 1);; 39 - val nsum : int -> int = <fun> 40 ]} 41 42 The function call [nsum n] computes the sum [1 +] … [+ nz] rather naively, hence the ··· 63 {1 Iteratively summing the first [n] integers} 64 65 {@ocaml run-on=load[ 66 - # let rec summing n total = 67 if n = 0 then 68 total 69 else 70 - summing (n - 1) (n + total);; 71 - val summing : int -> int -> int = <fun> 72 ]} 73 74 Function [summing] takes an additional argument: a running total. If ··· 119 {1 Silly Summing the First {e n} Integers} 120 121 {@ocaml run-on=load[ 122 - # let rec sillySum n = 123 if n = 0 then 124 0 125 else 126 - n + (sillySum (n - 1) + sillySum (n - 1)) / 2;; 127 - val sillySum : int -> int = <fun> 128 ]} 129 130 The function calls itself {m 2^n } times! Bigger inputs mean higher costs---but ··· 143 computed once and used twice: 144 145 {@ocaml run-on=load[ 146 - # let x = 2.0 in 147 let y = Float.pow x 20.0 in 148 - y *. (x /. y);; 149 - - : float = 2. 150 ]} 151 152 You can read [let x = e1 in e2] as assigning (or "binding") the name [x] with ··· 341 For example, recall our function [nsum]: 342 343 {@ocaml run-on=load[ 344 - # let rec nsum n = 345 if n = 0 then 346 0 347 else 348 - n + nsum (n - 1);; 349 - val nsum : int -> int = <fun> 350 ]} 351 352 Given {m n+1 }, it performs a constant amount of work (an addition and ··· 360 units. 361 362 {@ocaml run-on=load[ 363 - # let rec nsumsum n = 364 if n = 0 then 365 0 366 else 367 - nsum n + nsumsum (n - 1);; 368 - val nsumsum : int -> int = <fun> 369 ]} 370 371 We get the recurrence equations {m T(0)=1 } and {m T(n+1) = T(n)+n }. It is easy to
··· 31 {1 Summing the first {e n} integers} 32 33 {@ocaml run-on=load[ 34 + let rec nsum n = 35 if n = 0 then 36 0 37 else 38 + n + nsum (n - 1) 39 ]} 40 41 The function call [nsum n] computes the sum [1 +] … [+ nz] rather naively, hence the ··· 62 {1 Iteratively summing the first [n] integers} 63 64 {@ocaml run-on=load[ 65 + let rec summing n total = 66 if n = 0 then 67 total 68 else 69 + summing (n - 1) (n + total) 70 ]} 71 72 Function [summing] takes an additional argument: a running total. If ··· 117 {1 Silly Summing the First {e n} Integers} 118 119 {@ocaml run-on=load[ 120 + let rec sillySum n = 121 if n = 0 then 122 0 123 else 124 + n + (sillySum (n - 1) + sillySum (n - 1)) / 2 125 ]} 126 127 The function calls itself {m 2^n } times! Bigger inputs mean higher costs---but ··· 140 computed once and used twice: 141 142 {@ocaml run-on=load[ 143 + let x = 2.0 in 144 let y = Float.pow x 20.0 in 145 + y *. (x /. y) 146 ]} 147 148 You can read [let x = e1 in e2] as assigning (or "binding") the name [x] with ··· 337 For example, recall our function [nsum]: 338 339 {@ocaml run-on=load[ 340 + let rec nsum n = 341 if n = 0 then 342 0 343 else 344 + n + nsum (n - 1) 345 ]} 346 347 Given {m n+1 }, it performs a constant amount of work (an addition and ··· 355 units. 356 357 {@ocaml run-on=load[ 358 + let rec nsumsum n = 359 if n = 0 then 360 0 361 else 362 + nsum n + nsumsum (n - 1) 363 ]} 364 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 {1 Introduction} 4 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")] 10 ]} 11 12 A {e list} is an ordered series of elements; repetitions are significant. ··· 29 possible. 30 31 {@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")] 36 ]} 37 38 The infix operator [@] (also called [List.append]) concatenates two lists. ··· 47 }} 48 49 {@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] 56 ]} 57 58 The operator [::] (also called [List.cons] for “construct”), puts a new element on ··· 88 {1 Getting at the Head and Tail} 89 90 {@ocaml run-on=load[ 91 - # let null = function 92 | [] -> true 93 | 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] 115 ]} 116 117 The empty list has neither head nor tail. Applying [hd] or [tl] to [[]] ··· 136 types of their arguments and results. Note their types! 137 138 {@ocaml[ 139 - # null;; 140 - - : 'a list -> bool = <fun> 141 - # hd;; 142 - - : 'a list -> 'a = <fun> 143 - # tl;; 144 - - : 'a list -> 'a list = <fun> 145 ]} 146 147 Symbols ['a] and ['b] are called {e type variables} and stand for any types. Code ··· 153 {1 Computing the Length of a List} 154 155 {@ocaml[ 156 - # let rec nlength = function 157 | [] -> 0 158 | 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 164 ]} 165 166 {math ··· 179 To understand its role, consider the following faulty code: 180 181 {@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> 194 ]} 195 196 These are two declarations, not one. First we declare [nlength] to be a ··· 211 {1 Efficiently Computing the Length of a List} 212 213 {@ocaml run-on=load[ 214 - # let rec addlen n = function 215 | [] -> n 216 | x::xs -> addlen (n + 1) xs;; 217 - val addlen : int -> 'a list -> int = <fun> 218 - # addlen 0 [5; 6; 7];; 219 - - : int = 3 220 ]} 221 222 Recall that the use of [function] introduces an extra (unnamed) argument ··· 239 [addlen], supplying zero as the initial value of {m n }. 240 241 {@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 246 ]} 247 248 The recursive calls do not nest: this version is iterative. It takes {m O(1) } ··· 252 {1 Append: List Concatenation} 253 254 {@ocaml run-on=load[ 255 - # let rec append xs ys = 256 match xs, ys with 257 | [], ys -> ys 258 | 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] 266 ]} 267 268 Patterns can be as complicated as we like. Here, the two patterns are ··· 301 Let us consider one way to reverse a list. 302 303 {@ocaml run-on=load[ 304 - # let rec nrev = function 305 | [] -> [] 306 - | x::xs -> (nrev xs) @ [x];; 307 - val nrev : 'a list -> 'a list = <fun> 308 ]} 309 310 {@ocaml run-on=load[ 311 - # nrev [1; 2; 3];; 312 - - : int list = [3; 2; 1] 313 ]} 314 315 {math ··· 335 {1 Reversing a List in {m O(n) }} 336 337 {@ocaml run-on=load[ 338 - # let rec rev_app xs ys = 339 match xs, ys with 340 | [], ys -> ys 341 - | x::xs, ys -> rev_app xs (x::ys);; 342 - val rev_app : 'a list -> 'a list -> 'a list = <fun> 343 ]} 344 345 {math ··· 355 prepends them to [ys]. Now we may declare 356 357 {@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] 362 ]} 363 364 It is easy to see that this reverse function performs just {m n } conses, given ··· 387 program formats its results ultimately as strings. 388 389 {@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" 400 ]} 401 402 In a few programming languages, strings simply are lists of characters. In ··· 437 Consider the polymorphic types in these two function declarations: 438 439 {@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> 444 ]} 445 446 Explain why these types make logical sense, preventing run time type errors, even for expressions
··· 3 {1 Introduction} 4 5 {@ocaml run-on=load[ 6 + let x = [3; 5; 9];; 7 + let y = [(1, "one"); (2, "two")] 8 ]} 9 10 A {e list} is an ordered series of elements; repetitions are significant. ··· 27 possible. 28 29 {@ocaml run-on=load[ 30 + x @ [2; 10];; 31 + List.rev [(1, "one"); (2, "two")] 32 ]} 33 34 The infix operator [@] (also called [List.append]) concatenates two lists. ··· 43 }} 44 45 {@ocaml run-on=load[ 46 + let nil = [];; 47 + 1 :: nil;; 48 + 1 :: 2 :: nil 49 ]} 50 51 The operator [::] (also called [List.cons] for “construct”), puts a new element on ··· 81 {1 Getting at the Head and Tail} 82 83 {@ocaml run-on=load[ 84 + let null = function 85 | [] -> true 86 | x :: l -> false;; 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] 93 ]} 94 95 The empty list has neither head nor tail. Applying [hd] or [tl] to [[]] ··· 114 types of their arguments and results. Note their types! 115 116 {@ocaml[ 117 + null;; 118 + hd;; 119 + tl 120 ]} 121 122 Symbols ['a] and ['b] are called {e type variables} and stand for any types. Code ··· 128 {1 Computing the Length of a List} 129 130 {@ocaml[ 131 + let rec nlength = function 132 | [] -> 0 133 | x :: xs -> 1 + nlength xs;; 134 + nlength [];; 135 + nlength [5; 6; 7] 136 ]} 137 138 {math ··· 151 To understand its role, consider the following faulty code: 152 153 {@ocaml run-on=load[ 154 + let rec nlength [] = 0;; 155 + let rec nlength (x::xs) = 1 + nlength xs 156 ]} 157 158 These are two declarations, not one. First we declare [nlength] to be a ··· 173 {1 Efficiently Computing the Length of a List} 174 175 {@ocaml run-on=load[ 176 + let rec addlen n = function 177 | [] -> n 178 | x::xs -> addlen (n + 1) xs;; 179 + addlen 0 [5; 6; 7] 180 ]} 181 182 Recall that the use of [function] introduces an extra (unnamed) argument ··· 199 [addlen], supplying zero as the initial value of {m n }. 200 201 {@ocaml run-on=load[ 202 + let length xs = addlen 0 xs;; 203 + length [5; 6; 7; 8] 204 ]} 205 206 The recursive calls do not nest: this version is iterative. It takes {m O(1) } ··· 210 {1 Append: List Concatenation} 211 212 {@ocaml run-on=load[ 213 + let rec append xs ys = 214 match xs, ys with 215 | [], ys -> ys 216 | x::xs, ys -> x :: append xs ys;; 217 + append [1; 2; 3] [4];; 218 + let (@) = append;; 219 + [1; 2; 3] @ [4] 220 ]} 221 222 Patterns can be as complicated as we like. Here, the two patterns are ··· 255 Let us consider one way to reverse a list. 256 257 {@ocaml run-on=load[ 258 + let rec nrev = function 259 | [] -> [] 260 + | x::xs -> (nrev xs) @ [x] 261 ]} 262 263 {@ocaml run-on=load[ 264 + nrev [1; 2; 3] 265 ]} 266 267 {math ··· 287 {1 Reversing a List in {m O(n) }} 288 289 {@ocaml run-on=load[ 290 + let rec rev_app xs ys = 291 match xs, ys with 292 | [], ys -> ys 293 + | x::xs, ys -> rev_app xs (x::ys) 294 ]} 295 296 {math ··· 306 prepends them to [ys]. Now we may declare 307 308 {@ocaml run-on=load[ 309 + let rev xs = rev_app xs [];; 310 + rev [1; 2; 3] 311 ]} 312 313 It is easy to see that this reverse function performs just {m n } conses, given ··· 336 program formats its results ultimately as strings. 337 338 {@ocaml run-on=load[ 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" 344 ]} 345 346 In a few programming languages, strings simply are lists of characters. In ··· 381 Consider the polymorphic types in these two function declarations: 382 383 {@ocaml[ 384 + let id x = x;; 385 + let rec loop x = loop x 386 ]} 387 388 Explain why these types make logical sense, preventing run time type errors, even for expressions
+24 -84
site/notebooks/foundations/foundations4.mld
··· 16 They can be implemented in OCaml as follows: 17 18 {@ocaml[ 19 - # let rec take i = function 20 | [] -> [] 21 | x::xs -> 22 if i > 0 then x :: take (i - 1) xs 23 else [];; 24 - val take : int -> 'a list -> 'a list = <fun> 25 - # let rec drop i = function 26 | [] -> [] 27 | x::xs -> 28 if i > 0 then drop (i-1) xs 29 - else x::xs;; 30 - val drop : int -> 'a list -> 'a list = <fun> 31 ]} 32 33 Applications of [take] and [drop] will appear in future lectures. Typically, ··· 71 {1 Equality Tests} 72 73 {@ocaml[ 74 - # let rec member x = function 75 | [] -> false 76 | y::l -> 77 if x = y then true 78 - else member x l;; 79 - val member : 'a -> 'a list -> bool = <fun> 80 ]} 81 82 All the list functions we have encountered up to now have been “polymorphic”, ··· 106 {1 Building a List of Pairs} 107 108 {@ocaml[ 109 - # let rec zip xs ys = 110 match xs, ys with 111 | (x::xs, y::ys) -> (x, y) :: zip xs ys 112 - | _ -> [];; 113 - val zip : 'a list -> 'b list -> ('a * 'b) list = <fun> 114 ]} 115 116 {math \left.[x_1,\ldots,x_n]\atop ··· 134 function to the elements of another list {m [z_1,\ldots,z_n] }. 135 136 {@ocaml[ 137 - # let rec unzip = function 138 | [] -> ([], []) 139 | (x, y)::pairs -> 140 let xs, ys = unzip pairs in 141 - (x::xs, y::ys);; 142 - val unzip : ('a * 'b) list -> 'a list * 'b list = <fun> 143 ]} 144 145 Given a list of pairs, [unzip] has to build {e two} lists of ··· 160 inverts this operation. Their types reflect what they do: 161 162 {@ocaml[ 163 - # zip;; 164 - - : 'a list -> 'b list -> ('a * 'b) list = <fun> 165 - # unzip;; 166 - - : ('a * 'b) list -> 'a list * 'b list = <fun> 167 ]} 168 169 If the lists are of unequal length, [zip] discards surplus items at the ··· 181 but not every local binding can be eliminated as easily. 182 183 {@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 187 | [] -> ([], []) 188 - | xy :: pairs -> conspair (xy, unzip pairs);; 189 - val unzip : ('a * 'b) list -> 'a list * 'b list = <fun> 190 ]} 191 192 Making the function iterative yields [revUnzip] below, which is ··· 197 iteration. 198 199 {@ocaml[ 200 - # let rec revUnzip = function 201 | ([], xs, ys) -> (xs, ys) 202 | ((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> 206 ]} 207 208 {1 An Application: Making Change} ··· 218 }} 219 220 {@ocaml[ 221 - # let rec change till amt = 222 match till, amt with 223 | _, 0 -> [] 224 | [], _ -> raise (Failure "no more coins!") 225 | 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> 228 ]} 229 230 Although nobody considers making change for zero, this is the simplest way to ··· 251 and write a new [change] function. 252 253 {@ocaml[ 254 - # let rec change till amt = 255 match till, amt with 256 | _ , 0 -> [ [] ] 257 | [] , _ -> [] ··· 261 | cs :: css -> (c::cs) :: allc css 262 in 263 allc (change (c::till) (amt - c)) @ 264 - change till amt;; 265 - val change : int list -> int -> int list list = <fun> 266 ]} 267 268 Look at the type: the result is now a list of lists. ··· 292 {1 All Ways of Making Change --- Faster!} 293 294 {@ocaml[ 295 - # let rec change till amt chg chgs = 296 match till, amt with 297 | _ , 0 -> chg::chgs 298 | [] , _ -> chgs 299 | c::till , amt -> if amt < 0 then chgs 300 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> 304 ]} 305 306 We’ve added {e another} accumulating parameter! Repeatedly improving simple code ··· 342 How does this version of [zip] differ from the one above? 343 344 {@ocaml skip[ 345 - # let rec zip xs ys = 346 match xs, ys with 347 | (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 - (_::_, []) 394 ]} 395 396 {2 Exercise 4.4}
··· 16 They can be implemented in OCaml as follows: 17 18 {@ocaml[ 19 + let rec take i = function 20 | [] -> [] 21 | x::xs -> 22 if i > 0 then x :: take (i - 1) xs 23 else [];; 24 + let rec drop i = function 25 | [] -> [] 26 | x::xs -> 27 if i > 0 then drop (i-1) xs 28 + else x::xs 29 ]} 30 31 Applications of [take] and [drop] will appear in future lectures. Typically, ··· 69 {1 Equality Tests} 70 71 {@ocaml[ 72 + let rec member x = function 73 | [] -> false 74 | y::l -> 75 if x = y then true 76 + else member x l 77 ]} 78 79 All the list functions we have encountered up to now have been “polymorphic”, ··· 103 {1 Building a List of Pairs} 104 105 {@ocaml[ 106 + let rec zip xs ys = 107 match xs, ys with 108 | (x::xs, y::ys) -> (x, y) :: zip xs ys 109 + | _ -> [] 110 ]} 111 112 {math \left.[x_1,\ldots,x_n]\atop ··· 130 function to the elements of another list {m [z_1,\ldots,z_n] }. 131 132 {@ocaml[ 133 + let rec unzip = function 134 | [] -> ([], []) 135 | (x, y)::pairs -> 136 let xs, ys = unzip pairs in 137 + (x::xs, y::ys) 138 ]} 139 140 Given a list of pairs, [unzip] has to build {e two} lists of ··· 155 inverts this operation. Their types reflect what they do: 156 157 {@ocaml[ 158 + zip;; 159 + unzip 160 ]} 161 162 If the lists are of unequal length, [zip] discards surplus items at the ··· 174 but not every local binding can be eliminated as easily. 175 176 {@ocaml[ 177 + let conspair ((x, y), (xs, ys)) = (x::xs, y::ys);; 178 + let rec unzip = function 179 | [] -> ([], []) 180 + | xy :: pairs -> conspair (xy, unzip pairs) 181 ]} 182 183 Making the function iterative yields [revUnzip] below, which is ··· 188 iteration. 189 190 {@ocaml[ 191 + let rec revUnzip = function 192 | ([], xs, ys) -> (xs, ys) 193 | ((x, y)::pairs, xs, ys) -> 194 + revUnzip (pairs, x::xs, y::ys) 195 ]} 196 197 {1 An Application: Making Change} ··· 207 }} 208 209 {@ocaml[ 210 + let rec change till amt = 211 match till, amt with 212 | _, 0 -> [] 213 | [], _ -> raise (Failure "no more coins!") 214 | c::till, amt -> if amt < c then change till amt 215 + else c :: change (c::till) (amt - c) 216 ]} 217 218 Although nobody considers making change for zero, this is the simplest way to ··· 239 and write a new [change] function. 240 241 {@ocaml[ 242 + let rec change till amt = 243 match till, amt with 244 | _ , 0 -> [ [] ] 245 | [] , _ -> [] ··· 249 | cs :: css -> (c::cs) :: allc css 250 in 251 allc (change (c::till) (amt - c)) @ 252 + change till amt 253 ]} 254 255 Look at the type: the result is now a list of lists. ··· 279 {1 All Ways of Making Change --- Faster!} 280 281 {@ocaml[ 282 + let rec change till amt chg chgs = 283 match till, amt with 284 | _ , 0 -> chg::chgs 285 | [] , _ -> chgs 286 | c::till , amt -> if amt < 0 then chgs 287 else change (c::till) (amt - c) (c::chg) 288 + (change till amt chg chgs) 289 ]} 290 291 We’ve added {e another} accumulating parameter! Repeatedly improving simple code ··· 327 How does this version of [zip] differ from the one above? 328 329 {@ocaml skip[ 330 + let rec zip xs ys = 331 match xs, ys with 332 | (x::xs, y::ys) -> (x, y) :: zip xs ys 333 + | ([], []) -> [] 334 ]} 335 336 {2 Exercise 4.4}
+16 -80
site/notebooks/foundations/foundations5.mld
··· 57 lines of code. 58 59 {@ocaml[ 60 - # let nextrandom seed = 61 let a = 16807.0 in 62 let m = 2147483647.0 in 63 let t = a *. seed in 64 t -. m *. (floor (t /. m));; 65 - val nextrandom : float -> float = <fun> 66 - # let rec randlist (seed, seeds) = function 67 | 0 -> (seed, seeds) 68 - | n -> randlist (nextrandom seed, seed::seeds) (n-1);; 69 - val randlist : float * float list -> int -> float * float list = <fun> 70 ]} 71 72 We can now bind the identifier [rs] to a list of 10,000 random numbers. 73 74 {@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.; ...] 131 ]} 132 133 {1 Insertion Sort} ··· 135 An insert operation does {m n/2} comparisons on average. 136 137 {@ocaml[ 138 - # let rec ins x = function 139 | [] -> [x] 140 | y::ys -> if x <= y then x :: y :: ys 141 - else y :: ins x ys;; 142 - val ins : 'a -> 'a list -> 'a list = <fun> 143 ]} 144 145 {e Insertion sort} takes {m O(n^2)} comparisons on average: 146 147 {@ocaml[ 148 - # let rec insort = function 149 | [] -> [] 150 - | x::xs -> ins x (insort xs);; 151 - val insort : 'a list -> 'a list = <fun> 152 ]} 153 154 Items from the input are copied one at a time to the output. Each new item is ··· 191 {1 Quicksort: The Code} 192 193 {@ocaml[ 194 - # let rec quick = function 195 | [] -> [] 196 | [x] -> [x] 197 | a::bs -> ··· 203 else 204 part l (x::r) xs 205 in 206 - part [] [] bs;; 207 - val quick : 'a list -> 'a list = <fun> 208 ]} 209 210 Our OCaml quicksort copies the items. It is still pretty fast, and it is much ··· 236 {1 Append-Free Quicksort} 237 238 {@ocaml[ 239 - # let rec quik = function 240 | ([], sorted) -> sorted 241 | ([x], sorted) -> x::sorted 242 | a::bs, sorted -> ··· 248 else 249 part (l, x::r, xs) 250 in 251 - part ([], [], bs);; 252 - val quik : 'a list * 'a list -> 'a list = <fun> 253 ]} 254 255 The list [sorted] accumulates the result in the {e combine} stage of ··· 272 Merge joins two sorted lists. 273 274 {@ocaml[ 275 - # let rec merge = function 276 | [], ys -> ys 277 | xs, [] -> xs 278 | x::xs, y::ys -> 279 if x <= y then 280 x :: merge (xs, y::ys) 281 else 282 - y :: merge (x::xs, ys);; 283 - val merge : 'a list * 'a list -> 'a list = <fun> 284 ]} 285 286 Generalises insert to two lists, and does at most {m m+n-1} comparisons. ··· 304 {1 Top-down Merge sort} 305 306 {@ocaml[ 307 - # let rec tmergesort = function 308 | [] -> [] 309 | [x] -> [x] 310 | xs -> 311 let k = List.length xs / 2 in 312 let l = tmergesort (take k xs) in 313 let r = tmergesort (drop k xs) in 314 - merge (l, r);; 315 - Line 6, characters 28-32: 316 - Error: Unbound value take 317 ]} 318 319 {m O(n\log n)} comparisons in worst case
··· 57 lines of code. 58 59 {@ocaml[ 60 + let nextrandom seed = 61 let a = 16807.0 in 62 let m = 2147483647.0 in 63 let t = a *. seed in 64 t -. m *. (floor (t /. m));; 65 + let rec randlist (seed, seeds) = function 66 | 0 -> (seed, seeds) 67 + | n -> randlist (nextrandom seed, seed::seeds) (n-1) 68 ]} 69 70 We can now bind the identifier [rs] to a list of 10,000 random numbers. 71 72 {@ocaml[ 73 + let seed, rs = randlist (1.0, []) 10000 74 ]} 75 76 {1 Insertion Sort} ··· 78 An insert operation does {m n/2} comparisons on average. 79 80 {@ocaml[ 81 + let rec ins x = function 82 | [] -> [x] 83 | y::ys -> if x <= y then x :: y :: ys 84 + else y :: ins x ys 85 ]} 86 87 {e Insertion sort} takes {m O(n^2)} comparisons on average: 88 89 {@ocaml[ 90 + let rec insort = function 91 | [] -> [] 92 + | x::xs -> ins x (insort xs) 93 ]} 94 95 Items from the input are copied one at a time to the output. Each new item is ··· 132 {1 Quicksort: The Code} 133 134 {@ocaml[ 135 + let rec quick = function 136 | [] -> [] 137 | [x] -> [x] 138 | a::bs -> ··· 144 else 145 part l (x::r) xs 146 in 147 + part [] [] bs 148 ]} 149 150 Our OCaml quicksort copies the items. It is still pretty fast, and it is much ··· 176 {1 Append-Free Quicksort} 177 178 {@ocaml[ 179 + let rec quik = function 180 | ([], sorted) -> sorted 181 | ([x], sorted) -> x::sorted 182 | a::bs, sorted -> ··· 188 else 189 part (l, x::r, xs) 190 in 191 + part ([], [], bs) 192 ]} 193 194 The list [sorted] accumulates the result in the {e combine} stage of ··· 211 Merge joins two sorted lists. 212 213 {@ocaml[ 214 + let rec merge = function 215 | [], ys -> ys 216 | xs, [] -> xs 217 | x::xs, y::ys -> 218 if x <= y then 219 x :: merge (xs, y::ys) 220 else 221 + y :: merge (x::xs, ys) 222 ]} 223 224 Generalises insert to two lists, and does at most {m m+n-1} comparisons. ··· 242 {1 Top-down Merge sort} 243 244 {@ocaml[ 245 + let rec tmergesort = function 246 | [] -> [] 247 | [x] -> [x] 248 | xs -> 249 let k = List.length xs / 2 in 250 let l = tmergesort (take k xs) in 251 let r = tmergesort (drop k xs) in 252 + merge (l, r) 253 ]} 254 255 {m O(n\log n)} comparisons in worst case
+38 -72
site/notebooks/foundations/foundations6.mld
··· 202 basic ones supplied with the core OCaml language. 203 204 {@ocaml run-on=load[ 205 - # type vehicle = Bike 206 | Motorbike 207 | Car 208 - | Lorry;; 209 - type vehicle = Bike | Motorbike | Car | Lorry 210 ]} 211 212 {ul {- We have declared a {e new type} named [vehicle]. ··· 240 {1 Declaring a Function on Vehicles} 241 242 {@ocaml run-on=load[ 243 - # let wheels = function 244 | Bike -> 2 245 | Motorbike -> 2 246 | Car -> 4 247 - | Lorry -> 18;; 248 - val wheels : vehicle -> int = <fun> 249 ]} 250 251 {ul {- Datatype constructors can be used in patterns. ··· 261 {1 A Datatype whose Constructors have Arguments} 262 263 {@ocaml run-on=load[ 264 - # type vehicle = Bike 265 | Motorbike of int 266 | Car of bool 267 - | Lorry of int;; 268 - type vehicle = Bike | Motorbike of int | Car of bool | Lorry of int 269 ]} 270 {ul {- Constructors with arguments (like [Lorry]) are {e distinct values}. (So [Car true] is distinct from [Car false]). 271 }{- Different kinds of [vehicle] can belong to one list: [[Bike, Car true, Motorbike 450]] ··· 283 reference work). 284 285 {@ocaml run-on=load[ 286 - # type vehicle = Bike 287 | Motorbike of int (* engine size in CCs *) 288 | 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 291 ]} 292 293 The list shown on the slide represents a bicycle, a Reliant Robin and a large ··· 303 logic: 304 305 {@ocaml[ 306 - # let wheels = function 307 | Bike -> 2 308 | Motorbike _ -> 2 309 | Car robin -> if robin then 3 else 4 310 - | Lorry w -> w;; 311 - val wheels : vehicle -> int = <fun> 312 ]} 313 314 This function consists of four clauses: ··· 358 {1 Exceptions in OCaml} 359 360 {@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 368 ]} 369 370 Each [exception] declaration introduces a distinct sort of exception, which can ··· 379 further information: the integer {m n}. 380 381 {@ocaml[ 382 - # try 383 print_endline "pre exception"; 384 raise (NoChange 1); 385 print_endline "post exception"; 386 with 387 | 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 = () 394 ]} 395 396 The effect of [raise <expr>] is to jump to the most recently-encountered ··· 414 alternative to exceptions is to instead return a value of datatype [option]. 415 416 {@ocaml[ 417 - # let x = Some 1;; 418 - val x : int option = Some 1 419 ]} 420 421 [None] signifies an error, while [Some x] returns the solution {m x}. This ··· 427 {1 Making Change with Exceptions} 428 429 {@ocaml[ 430 - # exception Change;; 431 - exception Change 432 - # let rec change till amt = 433 match till, amt with 434 | _, 0 -> [] 435 | [], _ -> raise Change 436 | c::till, amt -> if amt < 0 then raise Change 437 else try c :: change (c::till) (amt - c) 438 - with Change -> change till amt;; 439 - val change : int list -> int -> int list = <fun> 440 ]} 441 442 In the Lists lectures, we considered the problem of making change. The greedy ··· 500 {1 Binary Trees, a Recursive Datatype} 501 502 {@ocaml run-on=load[ 503 - # type 'a tree = 504 Lf 505 - | Br of 'a * 'a tree * 'a tree;; 506 - type 'a tree = Lf | Br of 'a * 'a tree * 'a tree 507 ]} 508 509 {@ocaml run-on=load hidden[ 510 - # let tree_printer to_txt t = 511 let rec tree = function 512 | Lf -> TreePrinter.Lf 513 | Br (n, l, r) -> TreePrinter.Br (n, [tree l; tree r]) ··· 517 | TreePrinter.Br (n, _) -> to_txt n 518 in 519 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> 523 ]} 524 525 A data structure with multiple branching is called a “tree”. Trees can 526 represent mathematical expressions, logical formulae, computer programs, the 527 phrase structure of English sentences, etc. 528 529 - {x@ocaml run-on=load[ 530 - # let tree = Br(1, Br(2, Br(4, Lf, Lf), 531 Br(5, Lf, Lf)), 532 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> %} 541 ]} 542 543 ··· 548 OCaml lists are a datatype and could be declared as follows: 549 550 {@ocaml run-on=load[ 551 - # type 'a mylist = 552 | Nil 553 - | Cons of 'a * 'a mylist;; 554 - type 'a mylist = Nil | Cons of 'a * 'a mylist 555 ]} 556 557 We could even declare [::] as an infix constructor. The only ··· 564 that is recursive but not polymorphic. 565 566 {@ocaml run-on=load[ 567 - # type shape = 568 | Null 569 - | Join of shape * shape;; 570 - type shape = Null | Join of shape * shape 571 ]} 572 573 The datatype ['a option] (mentioned above) is the opposite -- it is ··· 576 {1 Basic Properties of Binary Trees} 577 578 {@ocaml run-on=load[ 579 - # let rec count = function 580 | Lf -> 0 (* number of branch nodes *) 581 | Br (v, t1, t2) -> 1 + count t1 + count t2;; 582 - val count : 'a tree -> int = <fun> 583 - # let rec depth = function 584 | Lf -> 0 (* length of longest path *) 585 - | Br (v, t1, t2) -> 1 + max (depth t1) (depth t2);; 586 - val depth : 'a tree -> int = <fun> 587 ]} 588 589 The invariant {m \texttt{count}(t)\le 2^{\texttt{depth}(t)} - 1} holds in the functions above. ··· 593 measure of a tree’s size: 594 595 {@ocaml run-on=load[ 596 - # let rec leaves = function 597 | Lf -> 1 598 - | Br (v, t1, t2) -> leaves t1 + leaves t2;; 599 - val leaves : 'a tree -> int = <fun> 600 ]} 601 602 This function is redundant because of a basic fact about trees, which can be ··· 624 Using the definition of ['a tree] from before: 625 626 {@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 629 ]} 630 631 Examine the following function declaration. What does [ftree (1, n)] accomplish? 632 633 {@ocaml[ 634 - # let rec ftree k n = 635 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> 638 ]} 639 640 {2 Exercise 6.4}
··· 202 basic ones supplied with the core OCaml language. 203 204 {@ocaml run-on=load[ 205 + type vehicle = Bike 206 | Motorbike 207 | Car 208 + | Lorry 209 ]} 210 211 {ul {- We have declared a {e new type} named [vehicle]. ··· 239 {1 Declaring a Function on Vehicles} 240 241 {@ocaml run-on=load[ 242 + let wheels = function 243 | Bike -> 2 244 | Motorbike -> 2 245 | Car -> 4 246 + | Lorry -> 18 247 ]} 248 249 {ul {- Datatype constructors can be used in patterns. ··· 259 {1 A Datatype whose Constructors have Arguments} 260 261 {@ocaml run-on=load[ 262 + type vehicle = Bike 263 | Motorbike of int 264 | Car of bool 265 + | Lorry of int 266 ]} 267 {ul {- Constructors with arguments (like [Lorry]) are {e distinct values}. (So [Car true] is distinct from [Car false]). 268 }{- Different kinds of [vehicle] can belong to one list: [[Bike, Car true, Motorbike 450]] ··· 280 reference work). 281 282 {@ocaml run-on=load[ 283 + type vehicle = Bike 284 | Motorbike of int (* engine size in CCs *) 285 | Car of bool (* true if a Reliant Robin *) 286 + | Lorry of int 287 ]} 288 289 The list shown on the slide represents a bicycle, a Reliant Robin and a large ··· 299 logic: 300 301 {@ocaml[ 302 + let wheels = function 303 | Bike -> 2 304 | Motorbike _ -> 2 305 | Car robin -> if robin then 3 else 4 306 + | Lorry w -> w 307 ]} 308 309 This function consists of four clauses: ··· 353 {1 Exceptions in OCaml} 354 355 {@ocaml[ 356 + exception Failure;; 357 + exception NoChange of int;; 358 + raise Failure 359 ]} 360 361 Each [exception] declaration introduces a distinct sort of exception, which can ··· 370 further information: the integer {m n}. 371 372 {@ocaml[ 373 + try 374 print_endline "pre exception"; 375 raise (NoChange 1); 376 print_endline "post exception"; 377 with 378 | NoChange _ -> 379 + print_endline "handled a NoChange exception" 380 ]} 381 382 The effect of [raise <expr>] is to jump to the most recently-encountered ··· 400 alternative to exceptions is to instead return a value of datatype [option]. 401 402 {@ocaml[ 403 + let x = Some 1 404 ]} 405 406 [None] signifies an error, while [Some x] returns the solution {m x}. This ··· 412 {1 Making Change with Exceptions} 413 414 {@ocaml[ 415 + exception Change;; 416 + let rec change till amt = 417 match till, amt with 418 | _, 0 -> [] 419 | [], _ -> raise Change 420 | c::till, amt -> if amt < 0 then raise Change 421 else try c :: change (c::till) (amt - c) 422 + with Change -> change till amt 423 ]} 424 425 In the Lists lectures, we considered the problem of making change. The greedy ··· 483 {1 Binary Trees, a Recursive Datatype} 484 485 {@ocaml run-on=load[ 486 + type 'a tree = 487 Lf 488 + | Br of 'a * 'a tree * 'a tree 489 ]} 490 491 {@ocaml run-on=load hidden[ 492 + let tree_printer to_txt t = 493 let rec tree = function 494 | Lf -> TreePrinter.Lf 495 | Br (n, l, r) -> TreePrinter.Br (n, [tree l; tree r]) ··· 499 | TreePrinter.Br (n, _) -> to_txt n 500 in 501 let svg = TreePrinter.svg_of_tree TreePrinter.default_params to_txt (tree t) in 502 + Mime_printer.push "image/svg" (Format.asprintf "%a" (Tyxml.Svg.pp ()) svg) 503 ]} 504 505 A data structure with multiple branching is called a “tree”. Trees can 506 represent mathematical expressions, logical formulae, computer programs, the 507 phrase structure of English sentences, etc. 508 509 + {@ocaml run-on=load[ 510 + let tree = Br(1, Br(2, Br(4, Lf, Lf), 511 Br(5, Lf, Lf)), 512 Br(3, Lf, Lf));; 513 + tree_printer string_of_int tree 514 ]} 515 516 ··· 521 OCaml lists are a datatype and could be declared as follows: 522 523 {@ocaml run-on=load[ 524 + type 'a mylist = 525 | Nil 526 + | Cons of 'a * 'a mylist 527 ]} 528 529 We could even declare [::] as an infix constructor. The only ··· 536 that is recursive but not polymorphic. 537 538 {@ocaml run-on=load[ 539 + type shape = 540 | Null 541 + | Join of shape * shape 542 ]} 543 544 The datatype ['a option] (mentioned above) is the opposite -- it is ··· 547 {1 Basic Properties of Binary Trees} 548 549 {@ocaml run-on=load[ 550 + let rec count = function 551 | Lf -> 0 (* number of branch nodes *) 552 | Br (v, t1, t2) -> 1 + count t1 + count t2;; 553 + let rec depth = function 554 | Lf -> 0 (* length of longest path *) 555 + | Br (v, t1, t2) -> 1 + max (depth t1) (depth t2) 556 ]} 557 558 The invariant {m \texttt{count}(t)\le 2^{\texttt{depth}(t)} - 1} holds in the functions above. ··· 562 measure of a tree’s size: 563 564 {@ocaml run-on=load[ 565 + let rec leaves = function 566 | Lf -> 1 567 + | Br (v, t1, t2) -> leaves t1 + leaves t2 568 ]} 569 570 This function is redundant because of a basic fact about trees, which can be ··· 592 Using the definition of ['a tree] from before: 593 594 {@ocaml[ 595 + type 'a tree = Lf | Br of 'a * 'a tree * 'a tree 596 ]} 597 598 Examine the following function declaration. What does [ftree (1, n)] accomplish? 599 600 {@ocaml[ 601 + let rec ftree k n = 602 if n = 0 then Lf 603 + else Br (k, ftree (2 * k) (n - 1), ftree (2 * k + 1) (n - 1)) 604 ]} 605 606 {2 Exercise 6.4}
+22 -38
site/notebooks/foundations/foundations7.mld
··· 31 keys do not need a concept of ordering, only equality. 32 33 {@ocaml[ 34 - # exception Missing 35 - exception Missing 36 - # let rec lookup a = function 37 | [] -> raise Missing 38 | (x, y) :: pairs -> 39 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> 44 ]} 45 46 To enter a new [(key, value)] pair, simply “cons” it to the list with [update]. ··· 78 {1 Lookup: Seeks Left or Right} 79 80 {@ocaml[ 81 - # exception Missing of string 82 - exception Missing of string 83 - # let rec lookup b = function 84 | Br ((a, x), t1, t2) -> 85 if b < a then 86 lookup b t1 ··· 89 else 90 x 91 | Lf -> raise (Missing b) 92 - val lookup : string -> (string * 'a) tree -> 'a = <fun> 93 ]} 94 95 This has guaranteed {m O(\log n)} access time {e if} the tree is balanced! ··· 107 {1 Update} 108 109 {@ocaml[ 110 - # let rec update k v = function 111 | Lf -> Br ((k, v), Lf, Lf) 112 | Br ((a, x), t1, t2) -> 113 if k < a then ··· 116 Br ((a, x), t1, update k v t2) 117 else (* a = k *) 118 Br ((a, v), t1, t2) 119 - val update : 'a -> 'b -> ('a * 'b) tree -> ('a * 'b) tree = <fun> 120 ]} 121 122 This is also {m O(\log n)} as it copies the path only, and {e not whole subtrees!} ··· 146 {1 Aside: Traversing Trees (3 Methods)} 147 148 {@ocaml[ 149 - # let rec preorder = function 150 | Lf -> [] 151 | Br (v, t1, t2) -> 152 - [v] @ preorder t1 @ preorder t2 153 - val preorder : 'a tree -> 'a list = <fun> 154 - # let rec inorder = function 155 | Lf -> [] 156 | Br (v, t1, t2) -> 157 - inorder t1 @ [v] @ inorder t2 158 - val inorder : 'a tree -> 'a list = <fun> 159 - # let rec postorder = function 160 | Lf -> [] 161 | Br (v, t1, t2) -> 162 postorder t1 @ postorder t2 @ [v] 163 - val postorder : 'a tree -> 'a list = <fun> 164 ]} 165 166 {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 eliminated from [quicksort] in the Sorting lecture. 192 193 {@ocaml[ 194 - # let rec preord = function 195 | Lf, vs -> vs 196 | 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 200 | Lf, vs -> vs 201 | 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 205 | Lf, vs -> vs 206 | Br (v, t1, t2), vs -> 207 postord (t1, postord (t2, v::vs)) 208 - val postord : 'a tree * 'a list -> 'a list = <fun> 209 ]} 210 211 One can prove equations relating each of these functions to its counterpart on ··· 280 {1 The Lookup Function} 281 282 {@ocaml[ 283 - # exception Subscript 284 - let rec sub = function 285 | Lf, _ -> raise Subscript (* Not found *) 286 | Br (v, t1, t2), k -> 287 if k = 1 then v 288 else if k mod 2 = 0 then 289 sub (t1, k / 2) 290 else 291 - sub (t2, k / 2) 292 - exception Subscript 293 - val sub : 'a tree * int -> 'a = <fun> 294 - # let rec sub = function (* Alternative implementation *) 295 | Lf, _ -> raise Subscript 296 | Br (v, t1, t2), 1 -> v 297 | Br (v, t1, t2), k when k mod 2 = 0 -> sub (t1, k / 2) 298 | Br (v, t1, t2), k -> sub (t2, k / 2) 299 - val sub : 'a tree * int -> 'a = <fun> 300 ]} 301 302 Notice that we have used a new keyword [when] above, which changes ··· 334 {1 The Update Function} 335 336 {@ocaml[ 337 - # let rec update = function 338 | Lf, k, w -> 339 if k = 1 then 340 Br (w, Lf, Lf) ··· 347 Br (v, update (t1, k / 2, w), t2) 348 else 349 Br (v, t1, update (t2, k / 2, w)) 350 - val update : 'a tree * int * 'a -> 'a tree = <fun> 351 ]} 352 353 The [update] function also divides the subscript repeatedly by two. When it
··· 31 keys do not need a concept of ordering, only equality. 32 33 {@ocaml[ 34 + exception Missing;; 35 + let rec lookup a = function 36 | [] -> raise Missing 37 | (x, y) :: pairs -> 38 if a = x then y 39 + else lookup a pairs;; 40 + let update (l, b, y) = (b, y) :: l 41 ]} 42 43 To enter a new [(key, value)] pair, simply “cons” it to the list with [update]. ··· 75 {1 Lookup: Seeks Left or Right} 76 77 {@ocaml[ 78 + exception Missing of string;; 79 + let rec lookup b = function 80 | Br ((a, x), t1, t2) -> 81 if b < a then 82 lookup b t1 ··· 85 else 86 x 87 | Lf -> raise (Missing b) 88 ]} 89 90 This has guaranteed {m O(\log n)} access time {e if} the tree is balanced! ··· 102 {1 Update} 103 104 {@ocaml[ 105 + let rec update k v = function 106 | Lf -> Br ((k, v), Lf, Lf) 107 | Br ((a, x), t1, t2) -> 108 if k < a then ··· 111 Br ((a, x), t1, update k v t2) 112 else (* a = k *) 113 Br ((a, v), t1, t2) 114 ]} 115 116 This is also {m O(\log n)} as it copies the path only, and {e not whole subtrees!} ··· 140 {1 Aside: Traversing Trees (3 Methods)} 141 142 {@ocaml[ 143 + let rec preorder = function 144 | Lf -> [] 145 | Br (v, t1, t2) -> 146 + [v] @ preorder t1 @ preorder t2;; 147 + let rec inorder = function 148 | Lf -> [] 149 | Br (v, t1, t2) -> 150 + inorder t1 @ [v] @ inorder t2;; 151 + let rec postorder = function 152 | Lf -> [] 153 | Br (v, t1, t2) -> 154 postorder t1 @ postorder t2 @ [v] 155 ]} 156 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. ··· 182 eliminated from [quicksort] in the Sorting lecture. 183 184 {@ocaml[ 185 + let rec preord = function 186 | Lf, vs -> vs 187 | Br (v, t1, t2), vs -> 188 + v :: preord (t1, preord (t2, vs));; 189 + let rec inord = function 190 | Lf, vs -> vs 191 | Br (v, t1, t2), vs -> 192 + inord (t1, v::inord (t2, vs));; 193 + let rec postord = function 194 | Lf, vs -> vs 195 | Br (v, t1, t2), vs -> 196 postord (t1, postord (t2, v::vs)) 197 ]} 198 199 One can prove equations relating each of these functions to its counterpart on ··· 268 {1 The Lookup Function} 269 270 {@ocaml[ 271 + exception Subscript;; 272 + let rec sub = function 273 | Lf, _ -> raise Subscript (* Not found *) 274 | Br (v, t1, t2), k -> 275 if k = 1 then v 276 else if k mod 2 = 0 then 277 sub (t1, k / 2) 278 else 279 + sub (t2, k / 2);; 280 + let rec sub = function (* Alternative implementation *) 281 | Lf, _ -> raise Subscript 282 | Br (v, t1, t2), 1 -> v 283 | Br (v, t1, t2), k when k mod 2 = 0 -> sub (t1, k / 2) 284 | Br (v, t1, t2), k -> sub (t2, k / 2) 285 ]} 286 287 Notice that we have used a new keyword [when] above, which changes ··· 319 {1 The Update Function} 320 321 {@ocaml[ 322 + let rec update = function 323 | Lf, k, w -> 324 if k = 1 then 325 Br (w, Lf, Lf) ··· 332 Br (v, update (t1, k / 2, w), t2) 333 else 334 Br (v, t1, update (t2, k / 2, w)) 335 ]} 336 337 The [update] function also divides the subscript repeatedly by two. When it
+36 -65
site/notebooks/foundations/foundations8.mld
··· 8 }} 9 10 {@ocaml[ 11 - # [(fun n -> n * 2); 12 (fun n -> n * 3); 13 - (fun n -> n + 1)];; 14 - - : (int -> int) list = [<fun>; <fun>; <fun>] 15 ]} 16 17 Progress in programming languages can be measured by what abstractions they ··· 47 The function [fun n -> n*2] is a {e doubling function}. 48 49 {@ocaml[ 50 - # fun n -> n * 2;; 51 - - : int -> int = <fun> 52 ]} 53 54 The main purpose of [fun]-notation is to package up small expressions that are to be ··· 57 [double], declared as follows: 58 59 {@ocaml[ 60 - # let double n = n * 2;; 61 - val double : int -> int = <fun> 62 ]} 63 64 The [fun] notation can also do pattern matching, and the [function] keyword ··· 66 are all equivalent, with the latter definitions bound to the [is_zero] value and the earlier ones anonymous: 67 68 {@ocaml[ 69 - # fun x -> match x with 0 -> true | _ -> false;; 70 - - : int -> bool = <fun> 71 ]} 72 73 {1 Curried Functions} ··· 76 the string concetenation operator [(^)] to illustrate how this works. 77 78 {@ocaml[ 79 - # (^);; 80 - - : string -> string -> string = <fun> 81 ]} 82 83 A short form for the definition of [prefix] is simply to pass multiple ··· 85 are equivalent in OCaml: 86 87 {@ocaml[ 88 - # let prefix = fun a -> fun b -> a ^ b;; 89 - val prefix : string -> string -> string = <fun> 90 ]} 91 92 Currying is the technique of expressing a function taking multiple arguments as nested functions, each taking a single argument. ··· 98 Currying is an alternative, where we {e nest} the [fun]-notation: 99 100 {@ocaml[ 101 - # fun k -> fun n -> n * 2 + k;; 102 - - : int -> int -> int = <fun> 103 ]} 104 105 Applying this curried function to the argument 1 yields another function, in which [k] has been replaced by 1: 106 107 {@ocaml[ 108 - # let fn = fun k -> fun n -> n * 2 + k;; 109 - val fn : int -> int -> int = <fun> 110 ]} 111 112 And this function, when applied to 3, yields the result 7. The two arguments are supplied one after another. ··· 123 This curried function syntax is nicer than nested [fun] binders: 124 125 {@ocaml[ 126 - # let prefix a b = a ^ b;; 127 - val prefix : string -> string -> string = <fun> 128 ]} 129 130 Curried functions allows {e partial application} (to the first argument). ··· 154 expressions: 155 156 {@ocaml[ 157 - # List.hd [dub; promote] "Hamilton";; 158 - Line 1, characters 9-12: 159 - Error: Unbound value dub 160 ]} 161 162 Here [List.hd] is applied to a list of functions, and the resulting function ··· 167 {1 Partial Application: A Curried Insertion Sort} 168 169 {@ocaml[ 170 - # let insort lessequal = 171 let rec ins x = function 172 | [] -> [x] 173 | y::ys -> if lessequal x y then x :: y :: ys ··· 177 | [] -> [] 178 | x::xs -> ins x (sort xs) 179 in 180 - sort;; 181 - val insort : ('a -> 'a -> bool) -> 'a list -> 'a list = <fun> 182 ]} 183 184 The sorting functions we discussed in earlier lectures are coded to sort floating-point ··· 193 Some examples of its use: 194 195 {@ocaml[ 196 - # insort (<=) [5; 3; 9; 8];; 197 - - : int list = [3; 5; 8; 9] 198 ]} 199 200 An obscure point: the syntax [(<=)] denotes the comparison operator as a ··· 205 {1 map: the “Apply to All” Function} 206 207 {@ocaml[ 208 - # let rec map f = function 209 | [] -> [] 210 - | x::xs -> (f x) :: map f xs;; 211 - val map : ('a -> 'b) -> 'a list -> 'b list = <fun> 212 ]} 213 214 The functional [map] applies a function to every element of a list, ··· 219 would require a preliminary function declaration: 220 221 {@ocaml[ 222 - # let rec sillylist = function 223 | [] -> [] 224 - | s::ss -> (s ^ "ppy") :: sillylist ss;; 225 - val sillylist : string list -> string list = <fun> 226 ]} 227 228 An expression containing several applications of functionals---such as our ··· 250 } 251 252 {@ocaml[ 253 - # let rec transp = function 254 | []::_ -> [] 255 | rows -> (map List.hd rows) :: 256 - (transp (map List.tl rows));; 257 - val transp : 'a list list -> 'a list list = <fun> 258 ]} 259 260 A matrix can be viewed as a list of rows, each row a list of matrix elements. ··· 356 {e Dot product} of two vectors---a {e curried function} 357 358 {@ocaml[ 359 - # let rec dotprod xs ys = 360 match xs, ys with 361 | [], [] -> 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> 368 ]} 369 370 {e Matrix product} 371 372 {@ocaml[ 373 - # let rec matprod arows brows = 374 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> 377 ]} 378 379 The [transp brows] converts {m B} into a list of columns, yielding a ··· 396 {1 List Functionals for Predicates} 397 398 {@ocaml[ 399 - # let rec exists p = function 400 | [] -> false 401 - | x::xs -> (p x) || (exists p xs);; 402 - val exists : ('a -> bool) -> 'a list -> bool = <fun> 403 ]} 404 405 A {e predicate} is a {e boolean-valued} function. ··· 413 predicate. If it finds a counterexample then it, too, stops searching. 414 415 {@ocaml[ 416 - # let rec all p = function 417 | [] -> true 418 - | x::xs -> (p x) && all p xs;; 419 - val all : ('a -> bool) -> 'a list -> bool = <fun> 420 ]} 421 422 The [filter] functional, like [map], transforms lists. It applies a ··· 427 {1 Applications of the Predicate Functionals} 428 429 {@ocaml[ 430 - # let member y xs = 431 - exists (fun x -> x=y) xs;; 432 - val member : 'a -> 'a list -> bool = <fun> 433 ]} 434 435 {e Testing whether two lists have no common elements} 436 437 {@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> 441 ]} 442 443 The Lists lecture presented the function [member], which tests whether a ··· 473 What does the following function do, and what are its uses? 474 475 {@ocaml[ 476 - # let sw f x y = f y x;; 477 - val sw : ('a -> 'b -> 'c) -> 'b -> 'a -> 'c = <fun> 478 ]} 479 480 {2 Exercise 8.2} ··· 498 for type ['a option]. 499 500 {@ocaml[ 501 - # type 'a option = None | Some of 'a;; 502 - type 'a option = None | Some of 'a 503 ]} 504 505 {2 Exercise 8.5} ··· 507 Recall the making change function of Lecture 4: 508 509 {@ocaml[ 510 - # let rec change till amt = 511 match till, amt with 512 | _ , 0 -> [ [] ] 513 | [] , _ -> [] ··· 517 | cs :: css -> (c::cs) :: allc css 518 in 519 allc (change (c::till) (amt - c)) @ 520 - change till amt;; 521 - val change : int list -> int -> int list list = <fun> 522 ]} 523 524 Function [allc] applies the function ‘cons a [c]’ to every element of a list. Eliminate it by
··· 8 }} 9 10 {@ocaml[ 11 + [(fun n -> n * 2); 12 (fun n -> n * 3); 13 + (fun n -> n + 1)] 14 ]} 15 16 Progress in programming languages can be measured by what abstractions they ··· 46 The function [fun n -> n*2] is a {e doubling function}. 47 48 {@ocaml[ 49 + fun n -> n * 2 50 ]} 51 52 The main purpose of [fun]-notation is to package up small expressions that are to be ··· 55 [double], declared as follows: 56 57 {@ocaml[ 58 + let double n = n * 2 59 ]} 60 61 The [fun] notation can also do pattern matching, and the [function] keyword ··· 63 are all equivalent, with the latter definitions bound to the [is_zero] value and the earlier ones anonymous: 64 65 {@ocaml[ 66 + fun x -> match x with 0 -> true | _ -> false 67 ]} 68 69 {1 Curried Functions} ··· 72 the string concetenation operator [(^)] to illustrate how this works. 73 74 {@ocaml[ 75 + (^) 76 ]} 77 78 A short form for the definition of [prefix] is simply to pass multiple ··· 80 are equivalent in OCaml: 81 82 {@ocaml[ 83 + let prefix = fun a -> fun b -> a ^ b 84 ]} 85 86 Currying is the technique of expressing a function taking multiple arguments as nested functions, each taking a single argument. ··· 92 Currying is an alternative, where we {e nest} the [fun]-notation: 93 94 {@ocaml[ 95 + fun k -> fun n -> n * 2 + k 96 ]} 97 98 Applying this curried function to the argument 1 yields another function, in which [k] has been replaced by 1: 99 100 {@ocaml[ 101 + let fn = fun k -> fun n -> n * 2 + k 102 ]} 103 104 And this function, when applied to 3, yields the result 7. The two arguments are supplied one after another. ··· 115 This curried function syntax is nicer than nested [fun] binders: 116 117 {@ocaml[ 118 + let prefix a b = a ^ b 119 ]} 120 121 Curried functions allows {e partial application} (to the first argument). ··· 145 expressions: 146 147 {@ocaml[ 148 + List.hd [dub; promote] "Hamilton" 149 ]} 150 151 Here [List.hd] is applied to a list of functions, and the resulting function ··· 156 {1 Partial Application: A Curried Insertion Sort} 157 158 {@ocaml[ 159 + let insort lessequal = 160 let rec ins x = function 161 | [] -> [x] 162 | y::ys -> if lessequal x y then x :: y :: ys ··· 166 | [] -> [] 167 | x::xs -> ins x (sort xs) 168 in 169 + sort 170 ]} 171 172 The sorting functions we discussed in earlier lectures are coded to sort floating-point ··· 181 Some examples of its use: 182 183 {@ocaml[ 184 + insort (<=) [5; 3; 9; 8] 185 ]} 186 187 An obscure point: the syntax [(<=)] denotes the comparison operator as a ··· 192 {1 map: the “Apply to All” Function} 193 194 {@ocaml[ 195 + let rec map f = function 196 | [] -> [] 197 + | x::xs -> (f x) :: map f xs 198 ]} 199 200 The functional [map] applies a function to every element of a list, ··· 205 would require a preliminary function declaration: 206 207 {@ocaml[ 208 + let rec sillylist = function 209 | [] -> [] 210 + | s::ss -> (s ^ "ppy") :: sillylist ss 211 ]} 212 213 An expression containing several applications of functionals---such as our ··· 235 } 236 237 {@ocaml[ 238 + let rec transp = function 239 | []::_ -> [] 240 | rows -> (map List.hd rows) :: 241 + (transp (map List.tl rows)) 242 ]} 243 244 A matrix can be viewed as a list of rows, each row a list of matrix elements. ··· 340 {e Dot product} of two vectors---a {e curried function} 341 342 {@ocaml[ 343 + let rec dotprod xs ys = 344 match xs, ys with 345 | [], [] -> 0.0 346 + | x::xs, y::ys -> (x *. y) +. (dotprod xs ys) 347 ]} 348 349 {e Matrix product} 350 351 {@ocaml[ 352 + let rec matprod arows brows = 353 let cols = transp brows in 354 + map (fun row -> map (dotprod row) cols) arows 355 ]} 356 357 The [transp brows] converts {m B} into a list of columns, yielding a ··· 374 {1 List Functionals for Predicates} 375 376 {@ocaml[ 377 + let rec exists p = function 378 | [] -> false 379 + | x::xs -> (p x) || (exists p xs) 380 ]} 381 382 A {e predicate} is a {e boolean-valued} function. ··· 390 predicate. If it finds a counterexample then it, too, stops searching. 391 392 {@ocaml[ 393 + let rec all p = function 394 | [] -> true 395 + | x::xs -> (p x) && all p xs 396 ]} 397 398 The [filter] functional, like [map], transforms lists. It applies a ··· 403 {1 Applications of the Predicate Functionals} 404 405 {@ocaml[ 406 + let member y xs = 407 + exists (fun x -> x=y) xs 408 ]} 409 410 {e Testing whether two lists have no common elements} 411 412 {@ocaml[ 413 + let disjoint xs ys = 414 + all (fun x -> all (fun y -> x<>y) ys) xs 415 ]} 416 417 The Lists lecture presented the function [member], which tests whether a ··· 447 What does the following function do, and what are its uses? 448 449 {@ocaml[ 450 + let sw f x y = f y x 451 ]} 452 453 {2 Exercise 8.2} ··· 471 for type ['a option]. 472 473 {@ocaml[ 474 + type 'a option = None | Some of 'a 475 ]} 476 477 {2 Exercise 8.5} ··· 479 Recall the making change function of Lecture 4: 480 481 {@ocaml[ 482 + let rec change till amt = 483 match till, amt with 484 | _ , 0 -> [ [] ] 485 | [] , _ -> [] ··· 489 | cs :: css -> (c::cs) :: allc css 490 in 491 allc (change (c::till) (amt - c)) @ 492 + change till amt 493 ]} 494 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 }} 77 78 {@ocaml[ 79 - # type 'a seq = 80 | Nil 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> 95 ]} 96 97 {m \tt Cons(x, xf)} has {e head} {m x} and {e tail function} {m xf} ··· 119 {1 The Infinite Sequence: {m k}, {m k+1}, {m k+2}, …} 120 121 {@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>) 130 ]} 131 132 Function [from] constructs the infinite sequence of integers starting ··· 142 {1 Consuming a Sequence} 143 144 {@ocaml[ 145 - # let rec get n s = 146 match n, s with 147 | 0, _ -> [] 148 | n, Nil -> [] 149 - | n, Cons (x, xf) -> x :: get (n-1) (xf ());; 150 - val get : int -> 'a seq -> 'a list = <fun> 151 ]} 152 153 The above code gets the first {m n} elements as a list. ··· 191 {1 Joining Two Sequences} 192 193 {@ocaml[ 194 - # let rec appendq xq yq = 195 match xq with 196 | Nil -> yq 197 - | Cons (x, xf) -> Cons(x, fun () -> appendq (xf ()) yq);; 198 - val appendq : 'a seq -> 'a seq -> 'a seq = <fun> 199 ]} 200 201 A more fair alternative: 202 203 {@ocaml[ 204 - # let rec interleave xq yq = 205 match xq with 206 | Nil -> yq 207 - | Cons (x, xf) -> Cons (x, fun () -> interleave yq (xf ()));; 208 - val interleave : 'a seq -> 'a seq -> 'a seq = <fun> 209 ]} 210 211 Most list functions and functionals have analogues on sequences, but strange ··· 233 Filtering lazy lists: 234 235 {@ocaml[ 236 - # let rec filterq p = function 237 | Nil -> Nil 238 | Cons (x, xf) -> 239 if p x then 240 Cons (x, fun () -> filterq p (xf ())) 241 else 242 - filterq p (xf ());; 243 - val filterq : ('a -> bool) -> 'a seq -> 'a seq = <fun> 244 ]} 245 246 The infinite sequence {m x}, {m f(x)}, {m f(f(x))}, … 247 248 {@ocaml[ 249 - # let rec iterates f x = 250 - Cons (x, fun () -> iterates f (f x));; 251 - val iterates : ('a -> 'a) -> 'a -> 'a seq = <fun> 252 ]} 253 254 The functional [filterq] demands elements of [xq] until it finds ··· 263 {1 Numerical Computations on Infinite Sequences} 264 265 {@ocaml[ 266 - # let next a x = (a /. x +. x) /. 2.0;; 267 - val next : float -> float -> float = <fun> 268 ]} 269 270 Close enough? 271 272 {@ocaml[ 273 - # let rec within eps = function 274 | Cons (x, xf) -> 275 match xf () with 276 | Cons (y, yf) -> 277 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> 289 ]} 290 291 Square Roots: 292 293 {@ocaml[ 294 - # let root a = within 1e6 (iterates (next a) 1.0);; 295 - val root : float -> float = <fun> 296 ]} 297 298 The {e Newton-Raphson method} is widely used for computing square roots. ··· 328 it be generalised to concatenate a sequence of sequences? What can go wrong? 329 330 {@ocaml[ 331 - # let rec concat = function 332 | [] -> [] 333 - | l::ls -> l @ concat ls;; 334 - val concat : 'a list list -> 'a list = <fun> 335 ]} 336 337 {2 Exercise 9.3}
··· 76 }} 77 78 {@ocaml[ 79 + type 'a seq = 80 | Nil 81 | Cons of 'a * (unit -> 'a seq);; 82 + let head (Cons (x, _)) = x;; 83 + let tail (Cons (_, xf)) = xf () 84 ]} 85 86 {m \tt Cons(x, xf)} has {e head} {m x} and {e tail function} {m xf} ··· 108 {1 The Infinite Sequence: {m k}, {m k+1}, {m k+2}, …} 109 110 {@ocaml[ 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 115 ]} 116 117 Function [from] constructs the infinite sequence of integers starting ··· 127 {1 Consuming a Sequence} 128 129 {@ocaml[ 130 + let rec get n s = 131 match n, s with 132 | 0, _ -> [] 133 | n, Nil -> [] 134 + | n, Cons (x, xf) -> x :: get (n-1) (xf ()) 135 ]} 136 137 The above code gets the first {m n} elements as a list. ··· 175 {1 Joining Two Sequences} 176 177 {@ocaml[ 178 + let rec appendq xq yq = 179 match xq with 180 | Nil -> yq 181 + | Cons (x, xf) -> Cons(x, fun () -> appendq (xf ()) yq) 182 ]} 183 184 A more fair alternative: 185 186 {@ocaml[ 187 + let rec interleave xq yq = 188 match xq with 189 | Nil -> yq 190 + | Cons (x, xf) -> Cons (x, fun () -> interleave yq (xf ())) 191 ]} 192 193 Most list functions and functionals have analogues on sequences, but strange ··· 215 Filtering lazy lists: 216 217 {@ocaml[ 218 + let rec filterq p = function 219 | Nil -> Nil 220 | Cons (x, xf) -> 221 if p x then 222 Cons (x, fun () -> filterq p (xf ())) 223 else 224 + filterq p (xf ()) 225 ]} 226 227 The infinite sequence {m x}, {m f(x)}, {m f(f(x))}, … 228 229 {@ocaml[ 230 + let rec iterates f x = 231 + Cons (x, fun () -> iterates f (f x)) 232 ]} 233 234 The functional [filterq] demands elements of [xq] until it finds ··· 243 {1 Numerical Computations on Infinite Sequences} 244 245 {@ocaml[ 246 + let next a x = (a /. x +. x) /. 2.0 247 ]} 248 249 Close enough? 250 251 {@ocaml[ 252 + let rec within eps = function 253 | Cons (x, xf) -> 254 match xf () with 255 | Cons (y, yf) -> 256 if abs_float (x -. y) <= eps then y 257 + else within eps (Cons (y, yf)) 258 ]} 259 260 Square Roots: 261 262 {@ocaml[ 263 + let root a = within 1e6 (iterates (next a) 1.0) 264 ]} 265 266 The {e Newton-Raphson method} is widely used for computing square roots. ··· 296 it be generalised to concatenate a sequence of sequences? What can go wrong? 297 298 {@ocaml[ 299 + let rec concat = function 300 | [] -> [] 301 + | l::ls -> l @ concat ls 302 ]} 303 304 {2 Exercise 9.3}
+15 -15
site/notebooks/oxcaml/local.mld
··· 6 let f () = 7 let u @ local = [6; 2; 8] in (* mode *) 8 let len = Base.List.length u in 9 - len;; 10 ]} 11 12 {@ocaml[ 13 let f () = 14 let local_ u = [6; 2; 8] in 15 let len = Base.List.length u in 16 - len;; 17 ]} 18 19 {@ocaml[ 20 let f () = 21 let u : int list @@ local = stack_ [6; 2; 8] in (* modality *) 22 let len = Base.List.length u in 23 - len;; 24 ]} 25 26 {@ocaml[ 27 let f () = 28 let u = local_ [6; 2; 8] in 29 let len = Base.List.length u in 30 - len;; 31 ]} 32 33 Other keywords to spot: [stack_], [global_], [@ global], [exclave_] and [[@local_opt]] ··· 53 let foo = 54 let local_ bar = ("region", "scope") in 55 bar in 56 - fst foo;; 57 ]} 58 59 {1 What does [local] mean?} ··· 86 {1 Hands-on} 87 88 {@ocaml[ 89 - # let monday () = let str = "mon" ^ "day" in str;; 90 ]} 91 92 {@ocaml[ 93 - # let bye () = let ciao = "sorry" in failwith ciao;; 94 ]} 95 96 {@ocaml[ 97 - # let make_counter () = 98 let counter = ref (-1) in 99 - fun () -> incr counter; !counter;; 100 ]} 101 102 {@ocaml[ 103 - # let state = ref "";; 104 - # let set () = state := "disco";; 105 ]} 106 107 {@ocaml[ 108 - # let rec map f = function [] -> [] | x :: u -> f x :: map f u;; 109 ]} 110 111 {@ocaml[ 112 - # let f1 (local_ u : int list) = [1; 2; 3];; 113 ]} 114 115 {@ocaml[ 116 - # let f2 (local_ u : int list) = u;; 117 ]} 118 119 {@ocaml[ 120 - # let f3 (local_ u : int list) = 42 :: u;; 121 ]} 122
··· 6 let f () = 7 let u @ local = [6; 2; 8] in (* mode *) 8 let len = Base.List.length u in 9 + len 10 ]} 11 12 {@ocaml[ 13 let f () = 14 let local_ u = [6; 2; 8] in 15 let len = Base.List.length u in 16 + len 17 ]} 18 19 {@ocaml[ 20 let f () = 21 let u : int list @@ local = stack_ [6; 2; 8] in (* modality *) 22 let len = Base.List.length u in 23 + len 24 ]} 25 26 {@ocaml[ 27 let f () = 28 let u = local_ [6; 2; 8] in 29 let len = Base.List.length u in 30 + len 31 ]} 32 33 Other keywords to spot: [stack_], [global_], [@ global], [exclave_] and [[@local_opt]] ··· 53 let foo = 54 let local_ bar = ("region", "scope") in 55 bar in 56 + fst foo 57 ]} 58 59 {1 What does [local] mean?} ··· 86 {1 Hands-on} 87 88 {@ocaml[ 89 + let monday () = let str = "mon" ^ "day" in str 90 ]} 91 92 {@ocaml[ 93 + let bye () = let ciao = "sorry" in failwith ciao 94 ]} 95 96 {@ocaml[ 97 + let make_counter () = 98 let counter = ref (-1) in 99 + fun () -> incr counter; !counter 100 ]} 101 102 {@ocaml[ 103 + let state = ref "";; 104 + let set () = state := "disco" 105 ]} 106 107 {@ocaml[ 108 + let rec map f = function [] -> [] | x :: u -> f x :: map f u 109 ]} 110 111 {@ocaml[ 112 + let f1 (local_ u : int list) = [1; 2; 3] 113 ]} 114 115 {@ocaml[ 116 + let f2 (local_ u : int list) = u 117 ]} 118 119 {@ocaml[ 120 + let f3 (local_ u : int list) = 42 :: u 121 ]} 122