Real World OCaml
Real World OCaml
Real World OCaml
TOC
Chapter 5 Records
5.1 Patterns And Exhaustiveness
5.2 Field Punning
5.3 Reusing Field Names
5.4 Functional Updates
Chapter 6 Variants
6.1 Catch-all Cases And Refactoring
6.2 Combining Records And Variants
6.3 Variants And Recursive Data Structures
6.4 Polymorphic Variants
1. Example: Terminal Colors Redux
2. When to Use Polymorphic Variants
Chapter 9 Functors
9.1 A Trivial Example
9.2 A Bigger Example: Computing With Intervals
1. Making The Functor Abstract
2. Sharing Constraints
3. Destructive Substitution
4. Using Multiple Interfaces
9.3 Extending Modules
Chapter 11 Objects
11.1 OCaml Obects
11.2 Object Polymorphism
11.3 Immutable Objects
11.4 When To Use Objects
11.5 Subtyping
1. Width Subtyping
2. Depth Subtyping
3. Variance
4. Narrowing
5. Subtyping vs Row Polymorphism
Chapter 12 Classes
12.1 OCaml classes
12.2 Class Parameters And Polymorphism
12.3 Object Types As Interfaces
1. Functional Iterators
12.4 Inheritance
12.5 Class Types
12.6 Open Recursion
12.7 Private Methods
12.8 Binary Methods
12.9 Virtual Classes And Methods
12.10 Initializers
12.11 Multiple Inheritance
1. How Names Are Resolved
2. Mixins
3. Displaying Animated Shapes
Notes:
utop # sqrt 9. ;;
- : float = 3.
Notes:
Function arguments are separated by spaces.
Floats and integers are distinct, both in literals ( 9. ) and operators (+.)
let x = 3.5;;
utop # let x = 3.5;;
val x : float = 3.5
Float.of_int is the function of_int in module Float (note beginning must be capital
letter)
# let even x =
x mod 2 = 0 ;;
val even : int -> bool = <fun>
# sum_if_true even 3 4;;
- : int = 4
# sum_if_true even 2 4;;
- : int = 6
Note that (unlike in Haskell) = serves as the equality check operator besides the
binding operator (In Haskell, =, ==)
Note: explicit type annotation for each argument, then for return type just before
= in the function definition
1. Type Inference
2. Lists
# let languages = ["OCaml";"Perl";"C"];;
val languages : string list = ["OCaml"; "Perl"; "C"]
Note: comments with (* *) Same format for single line and multiline comments
let .. in example
# let log_entry maybe_time message =
let time =
match maybe_time with
| Some x -> x
| None -> Time.now ()
in
Time.to_sec_string time ^ " -- " ^ message
;;
Note the variable on the *right* side of the = is what is used in the function
body. The record parameter names (here x and y) are on the left
Field Punning: When the record field and function parameter names are the same, we
don't have to write them both down.
so
# let magnitude { x ; y } = sqrt (x ** 2. +. y ** 2.);;
Variants
then
# type scene_element =
| Circle of circle_desc
| Rect of rect_desc
| Segment of segment_desc
;;
type scene_element =
Circle of circle_desc
| Rect of rect_desc
| Segment of segment_
declaring
updating
# numbers;;
- : int array = [|1; 2; 4; 4|]
extracting
utop # numbers.(0);;
- : int = 1
Record fields are immutable by default, but can be explicitily declared mutable
type running_sum =
{ mutable sum: float;
mutable sum_sq: float; (* sum of squares *)
mutable samples: int;
}
;;
3. Refs
Single mutable values are created by ref. The ref type comes predefined in the
stdlib but there is nothing special about it. It is justa record with one field.
Some syntax to make creating updating and extracting values (from refs) convenient.
for loop
# let permute array =
let length = Array.length array in
for i = 0 to length - 2 do
(* pick a j to swap with *)
let j = i + Random.int (length - i) in
(* Swap i and j *)
let tmp = array.(i) in
array.(i) <- array.(j);
array.(j) <- tmp
done
;;
val permute : 'a array -> unit = <fun>
While Loop
(* in sum.ml *)
open Core.Std
let rec read_and_accumulate accum =
let line = In_channel.input_line In_channel.stdin in
match line with
| None -> accum
| Some x -> read_and_accumulate (accum +. Float.of_string x)
let () =
printf "Total: %F\n" (read_and_accumulate 0.)
e.g:
# area_of_ring 1. 3.;;
- : float = 25.1327412287
utop # myints;;
- : int list = [1; 2; 3]
utop # mystrings;;
- : string list = ["one"; "two"; "three"]
Using a pattern in a let binding makes sense when the pattern is *irrefutable*,
i.e, when *any* value of the type in question is guaranteed to match the pattern.
Tuples and records patterns are irrefutable.
2.2 Functions
1. Anonymous Functions
2. Multiargument Functions
are curried. -> associates to the right
3. Recursive Functions
letrec find_first_stutter ls =
match ls with
| [] | [_] -> None (* zero element or single element lists don't
have repeated elements)
| first :: second :: rest -> if first == second then Some first
else find_first_stutter (second::rest) ;;
Functions whose names begin with one of a set of symbols {! $ .. +} are considered
infix.
utop # 2 + 6 ;;
- : int = 12
Upto now function arguments have been specified *positionally*. They can also be
defined by name , i.e by labels
label punning
let num = 3 in
let denom = 4 in
ratio ~num ~denom;;
- : float = 0.75
7. Optional arguments
This is a common enough situation that there is some special syntax for this
(some weirdness when you want to explicitly pass Some/None as a value for optional
parameter. Elided.
More weirdness about choosing between labels and options etc etc.
Basically don't use these. Just do 'normal' FP as with Haskell.
Chapter 3 Lists