Ocaml_cheatsheet

OCaml Cheatsheet

View on GitHub

OCaml Cheatsheet

Website: jonowoodhouse.github.io/Ocaml_cheatsheet/

View the cheatsheet.ml source code file for great examples of using Ocaml.


open Core

let () = print_endline "hello world"

let variables_example =
  (* ------------------------------------------------------------
     Variables
     ------------------------------------------------------------ *)
  let x = 5 in
  let real = 9. (* float (no trailing zero required) *) in
  let s = "a string" in

  (* ------------------------------------------------------------
     Annotated variables
     ------------------------------------------------------------ *)
  let y : int = 6 in
  let (z : int) = 7 in

  (* ------------------------------------------------------------
     Annotated return type - [calc] returns an int
     ------------------------------------------------------------ *)
  let calc x y s : int =
    printf "A %s has %i lives\n" s (x + y);
    x + y
  in

  (* ------------------------------------------------------------
     Renaming arguments
     ------------------------------------------------------------ *)
  let f ~a:renamed_a = renamed_a * 2 in

  (* ------------------------------------------------------------
     Printing to the screen
     ------------------------------------------------------------ *)
  printf "%d %d %d %f %s %i\n" x y z real s (f ~a:50);
  print_s [%message "Description" (s : string)];
  print_s (String.sexp_of_t s);
  (* This uses: https://github.com/janestreet/ppx_custom_printf*)
  printf !"%{sexp:string} %{sexp#mach:string} %{String}\n" s s s;
  let (_ : int) = calc 5 4 "cat" in

  (* ------------------------------------------------------------
     Recursion
     ------------------------------------------------------------ *)
  let rec fold list ~init ~accum =
    match list with [] -> init | hd :: tl -> fold tl ~init:(accum init hd) ~accum
  in

  (* ------------------------------------------------------------
     Anonymous function (fun keyword)
     ------------------------------------------------------------ *)
  printf "%i\n" (fold [ 1; 2; 3 ] ~init:0 ~accum:(fun init elem -> init + elem))

(* ------------------------------------------------------------
   Records - Construction, destruction, annotation and renaming
   ------------------------------------------------------------ *)
type contact = { name : string; mobile : string; birth_year : int } [@@deriving sexp]

let records_example =
  (* record construction *)
  let c = { name = "Adam"; mobile = "012345678"; birth_year = 1995 } in
  printf "%s %s %i\n" c.name c.mobile c.birth_year;
  printf !"%{sexp:contact}\n" c;
  let create_contact name mobile birth_year = { name; mobile; birth_year } in
  let c2 = create_contact "James" "999999999" 1988 in
  (* Use dot notation *)
  let print1 x = printf "%s %s %i\n" x.name x.mobile x.birth_year in
  (* Use record deconstruction *)
  let print2 { name; mobile; birth_year } (* much better *) =
    printf "%s %s %i\n" name mobile birth_year
  in
  (* use argument renaming and annotated variable *)
  let print3 ({ name; mobile; birth_year = b } : contact) = printf "%s %s %i\n" name mobile b in
  let print4 c =
    (* use record deconstruction *)
    let { name = n; mobile = m; birth_year } = c in
    printf "%s %s %i\n" n m birth_year
  in
  print1 c;
  print2 c;
  print3 c;
  print4 c2

(* ------------------------------------------------------------
   Record Types - records (types) in modules
   ------------------------------------------------------------ *)
module File = struct
  type t = { file_name : string; size : int; attributes : int } [@@deriving sexp]

  let to_string t = if t.attributes > 700 then String.uppercase t.file_name else t.file_name
end

let record_types_example1 =
  let create_directory_entry file_name size attributes = { File.file_name; size; attributes } in
  let is_small_file file =
    let { File.file_name = _; size; attributes = _ } = file in
    size < 1000
  in
  let file = create_directory_entry "temp.log" 100 755 in
  printf !"%{sexp:File.t}\n" file;
  (* ppx uses File.to_string *)
  printf !"%{File} : is_small_file=%b\n" file (is_small_file file)

(* ------------------------------------------------------------
   Record Types - 2nd example
   ------------------------------------------------------------ *)
module Price = struct
  type t = { x : float }

  let create x = { x }
end

let record_types_example2 =
  let price1 = Price.create 5.50 in
  let (price2 : Price.t) = { x = 6.50 } in
  (ignore price1, price2)

(* ------------------------------------------------------------
   Default arguments, named parameters and optional arguments
   ------------------------------------------------------------ *)
let arguments_example =
  (* by is optional but resolves to type int (not opional int)*)
  let increment ?(by = 1) x = x + by in
  let inc ?by x = match by with None -> x + 1 | Some by -> x + by in
  let incr ~by x = x + by in
  printf "0 inc = %d %d %d\n" (increment 0) (inc 0) (incr 0 ~by:1);
  printf "0 inc by 2 = %d %d %d %d\n" (increment 0 ~by:2) (inc 0 ~by:2) (inc 0 ?by:(Some 2))
    (incr 0 ~by:2)

(* ------------------------------------------------------------
   Tuples/Pairs (often better to use a record though)
   Open modules
   ------------------------------------------------------------ *)
let tuples_example =
  let gps_position latitude longitude = (latitude, longitude) in
  let sydney = gps_position (-33.865143) 151.209900 in
  let google_maps gps =
    let open Float in
    "https://www.google.com/maps/search/" ^ to_string (fst gps) ^ "," ^ to_string (snd gps) ^ "/"
  in
  printf "Google Maps URL for Sydney is %s\n" (google_maps sydney)



OCaml Terminology

Term Definition
annonymous function fun i -> 2 * i
applicative Some modules aren't quite monads. They have a [map] function like a Monad but not a [bind] function. [Command] is an example of a Applicative.
capitalisation Modules are Capitalised. functions and values are not.
destructive substitution with type t:=t (TODO explain more)
early binding runs at app start e.g. let two_pi = 2.0 *. Float.pi
first-order functions Functions that operate on normal data elements (e.g. ints, strings, records, variants etc.) See also high-order functions.
high-order functions Functions that take other functions as arguments or return functions. See also first-order functions
identity function Fn.id
interface, signature, module type are all used interchangeably
polymorphic functions functions that act over values with many different types. Similar to templates in C++ and Generics in C# and Java
record A bit like a struct in C.
type person = {age : int; name : string}
record type A record inside a module. module Foo = struct
type t = {bar : int; baz : string }
end
type parameter ['a] is a type parameter. Also known as a type variable. Forms a paramaterised type in a 'a pair.
val used in signatures, module signatures or in .mli files
variant type color = | Red | Green | Blue
variant - polymorphic variant `Red `Green `Blue etc.

Compiling cheatsheet.ml

	eval `opam config env`
	dune build @all
	_build/default/cheatsheet.exe

My OCaml programming environment

Opam

# TODO: complete this list
opam install dune utop ocamlformat core async merlin

Dune

in an empty folder:

	eval `opam config env`
	dune init executable dune_example
	dune build @all
	_build/default/main.exe

Ocamlformat

Other Tips

Further Reading

TODO