Speedrunning OCaml
#post #ocaml #functional-programming #programming-language #guide
One file going over OCaml essentials, inspired by Hype for Types’s 15-150 crash course. We assume some knowledge of Standard ML and Rust here.
(* == COMMENTS ==
just do SML comments :)
*)
(* blah blah blah *)
(* blah blah blah (* nested blah blah blah *) *)
(* == VALUE DECLARATIONS ==
- instead of using `val`, use `let`
- tuples work without parens
- replace `real` with `float`
note tuple evaluation is right to left
*)
let x : int = 1
let x : string = "hello"
let x : bool = false
let x : char = 'x'
let x : float = 3.14159
let x : int * int * string = (1, 2 + 3, "world")
let x : int * int * string = 1, 2 + 3, "world"
(* == BUILT IN OPERATIONS ==
- use `(` `)` to make operation a function
- use `.` after int operations to make it float operation
- `-` is polymorphic for `float` and `int`
- `~-` is the `int` only version
- `~-.` is the `float` only version
*)
let 11 = 5 + 6
let 2 = 5 mod 3
let true = (5 + 6) = (+) 5 6
let r : float = 3.14159 *. 2.0 +. 3.0 /. 34.0
(* == EXPRESSIONS ==
they should work as expected
*)
let r : int = 2 * 2 + 3
let r : string = "hello" ^ " " ^ "world"
let r : string = if -1 < 0 then "reasonable" else "absurd"
(* == FUNCTION DECLARATIONS ==
- instead of using `fun`, use `let` or `let rec`
- use `let rec` for recursive function
- curry works as expected
- function clauses do not exist, use `match` instead
- `and` still works for mutual recursion
- use `(` `)` to define infix functions
*)
let incr (x : int) : int = x + 1
let incr x = x + 1
let rec loop x = loop (x + 1)
let add x y = x + y
let rec fact n = if n = 0 then 1 else n * fact (n - 1)
let rec fact n = match n with
| 0 -> 1
| n -> n * fact (n - 1)
let rec
is_divisible_by_three = function | 0 -> true | n -> is_not_divisible_by_three (n - 1)
and
is_not_divisible_by_three = function | 0 -> false | 1 -> false | n -> is_divisible_by_three (n - 2)
let (>>=) o f = match o with
| None -> None
| Some x -> f x
(* == LAMBDA FUNCTIONS ==
- instead of `fn`, write `fun` or `function`
- use `fun` to curry
- use `function` to pattern match
- replace `=>` with `->`
*)
let square = function x -> x * x
let mult = fun x y -> x * y
let rec fact = function | 0 -> 1 | n -> n * fact (n - 1)
(* == LET IN END ==
the OCaml version:
- does not have `end`
- keep nesting instead of having multiple declarations between `let` and `in`
*)
let r : int =
let a = 1 in
let b = a * 2 in
let c = a + b in
a + b + c
(* == PATTERN MATCHING ==
- add `|` before the first clause
- replace `=>` with `->`
- pattern with conditional works like in Rust, just replace `if` with `when`
- alias pattern using `as`
*)
let r: string * int = match Some 3 with
| None -> ("nothing", -1)
| Some x when x = 3 -> ("something exactly 3", x)
| Some x -> ("something not 3", x)
let p = (2, 3)
let ((x, y) as p') = p
(* == LISTS ==
- use `;` instead of `,`
- `::` and `@` should work as expected
- `nil` won't work
note:
- `,` would make a tuple, even without parens, somewhat like python
*)
let l : int list = [150; 210; 122; 251; 451]
let l : (int * int) list = [15, 150; 15, 210; 15, 122; 15, 251; 15, 451]
let l : int list = 4::3::[]
let l : int list = [1; 2] @ [3; 4]
(* == DATATYPES ==
- replace `datatype` with `type`
- first letter of constructor must be uppercase
- add `|` before first constructor
notes:
- `type` aliases still work
- constructors cannot be passed in as if they are functions, use lambda instead
- the built in `option` constructors are `Some` and `None`
*)
type 'a another_option = | Nothing | Something of 'a
type 'a tree = | Empty | Node of 'a tree * 'a * 'a tree
type 'a labelled_rose = | Rose of 'a * string * 'a labelled_rose list
type point = int * int
(* == POLYMORPHISM ==
they should work as expected
*)
(* 'a -> 'b *)
let rec loop x = loop x
(* 'a * 'b -> 'a *)
let fst (x, y) = x
(* 'a list -> ('a -> 'b) -> 'b list *)
let rec map l f =
match l with
| [] -> []
| x::xs -> (f x)::(map xs f)
(* THE HOFS
find some of them in the `List` module
*)
(* 'a list -> int -> 'a *)
let nth = List.nth
(* ('a -> 'b) -> 'a list -> 'b list *)
let map = List.map
(* ('a -> bool) -> 'a list -> 'a lists *)
let filter = List.filter
(* ARRAYS
whatever this is
*)
let arr: int array = [|150; 210; 122; 251; 451|]
let 150 = arr.(0)
(* == SIDE EFFECTS AND IMPERATIVE ==
- use `print_endline : string -> unit` to print
- use `;` to chain together multiple things that return unit
- use `[@@deriving show]` to do something like deriving a display trait
- useful things to derive: `show`, `ord`, `hash`, `eq`
*)
let () = print_string "hello world\n"
let () = print_endline "hello world"
let () = Printf.printf "%s%d%s%c" "this is a number: " 42 "; and this is a char: " 'c'
let print_and_pass_through x =
print_endline x;
x
(* this generates `show_tree : tree -> string` and `tree_show : tree -> string`! *)
type tree = | Leaf of int | Node of tree * tree [@@deriving show]
let t = Node(Node(Leaf(2), Leaf(3)), Leaf(4))
let () = print_endline (tree_show t);
(* == NAMED AND OPTIONAL ARGUMENTS ==
- put `~` in front of argument that shall be named
- when applying function, pass `variable` to `name` by `~name:variable`
- a shorthand of `~x:x` is `~x`
- a unit argument is needed for functions taking optional arguments
*)
let takeslotsofarguments ~a ~b ~c ~d = ((a + b) * c) / d
let _ = takeslotsofarguments ~a:3 ~c:5 ~d:8 ~b:2
let _ =
let a = 3 in
let c = 5 in
takeslotsofarguments ~a ~c ~d:8 ~b:2
let allargsoptional ?(a = 3) ?(b = 2) () = a + b
let _ = allargsoptional ()
let _ = allargsoptional ~a:3 ()
let _ =
let b = 4 in
allargsoptional ~b ()
(* == RECORD TYPES ==
- use `;` to separate fields
- record types must be declared
- get things out buy `.` or pattern matching similar to Rust
- functional record updates using `with`
*)
type brewer = | V60 | Frenchpress | Espressomachine | Aeropress | Siphon | Coldbrew | Mokapot
type brew = {
coffee_mass: float;
grind_setting: int;
water_mass: float;
brew_time: int;
brewer: brewer;
}
let b = {coffee_mass = 16.0; grind_setting = 182; water_mass = 240.0; brew_time = 180; brewer = V60;}
let g = b.grind_setting
let {grind_setting = g; _} = b
let b' = {b with brewer = Frenchpress}
References: