OCaml


General

Partial application of function

# (=) 3 2;;
- : bool = false

# (=) 3 3;;
- : bool = true

List

https://ocaml.org/manual/5.2/api/List.html

Flip function: Fun.flip

# Fun.flip;;
- : ('a -> 'b -> 'c) -> 'b -> 'a -> 'c = <fun>

# List.mem;;
- : 'a -> 'a list -> bool = <fun>

# Fun.flip List.mem;;
- : '_weak1 list -> '_weak1 -> bool = <fun>

# Fun.flip List.mem [2;3];;
- : int -> bool = <fun>

# Fun.flip List.mem [2;3] 4;;
- : bool = false

# Fun.flip List.mem [2;3] 3;;
- : bool = true

Optional arguments

Like Labeled arguments, but with a default value and ? instead of a tilde.

>>> let foo ?(a=3) b = a + b;;
val foo : ?a:int -> int -> int = <fun>

>>> foo 2;;
- : int = 5

(* Overriding default value *)
>>> foo ~a:10 2;;
- : int = 12

(* Yeah, order doesn't matter *)
>>> foo 2 ~a:10;;
- : int = 12

>>> foo ~a:10;;
- : int -> int = <fun>

Reference: https://v2.ocaml.org/manual/lablexamples.html#s:optional-arguments

(|>) operator

It's like a reversed apply. ʳ

Function can be made to appear on RHS and its argument in LHS.

(|>);;
- : 'a -> ('a -> 'b) -> 'b = <fun>

0.0 |> sin;;
- : float = 0.

sin 0.0;;
- : float = 0.

Useful to make a 'pipeline' where the value flows from the left to the right. As in:

let simple_process s =
  Str.split Owl_nlp_utils.regexp_split s
  |> List.filter (fun x -> String.length x > 1)
  |> String.concat " "
  |> String.lowercase_ascii
  |> Bytes.of_string

(forgot from where I got this snippet..)

Empty type

We can make 'empty types'. ie, types without even a single constructor. ¹

Like:

type empty = |

Lack of constructors means it's impossible to construct a value of type empty.

Explicit subtyping info in type variables

Via variance annotations.

By default, type variables are covariant.

ocaml infers them, but the explicit notation can be helpful in the 'interface' of modules (ocaml analogue of structures).

References:

Reference (variables)

Mutable values.

# incr;;
- : int ref -> unit = <fun>

# let r = ref 0;;
val r : int ref = {contents = 0}

# !r;;
- : int = 0

# incr r;;
- : unit = ()

# !r;;
- : int = 1

Record types

type person = {
    name: string;
    age: int
}

mutable keyword in ocaml

Modifiable values. ie, non-pure.

mutable is not part of the type. Just property of the variable.

type point = {
    x: int;
    mutable y: int
}

# let p = {x=3; y=4};;
val p : point = {x = 3; y = 4}

# p.x <- 10
Error: The record field x is not mutable

# p.y <- 10;;
- : unit = ()
# p
- : point = {x = 3; y = 10}

References:

Tilde in arguments

They are labelled arguments.

https://ocaml.org/docs/labels

let rec range ~first:a ~last:b =
  if a > b then []
  else a :: range ~first:(a+1) ~last:b

# range
- : first:int -> last:int -> int list = <fun>
(* Show the argument labels! *)

# range 3 5
- : int list = [3; 4; 5]

(* Now argument order can be changed *)
# range ~last:10 ~first:3;;
- : int list = [3; 4; 5; 6; 7; 8; 9; 10]

Multi-line strings

Use within {| and |}.

# {| hello
   world
   |};;
- : string = " hello\n   world\n   "

pattern matching

See: https://v2.ocaml.org/manual/patterns.html

Can use function to pattern match without actually naming variables:

(* Given two lists, check if their concatenation is nil *)
let is2Nil = function
  | [], [] -> true
  | _, _ -> false
(* is2Nil : 'a list * 'b list -> bool *)

Or can use match as in Coq:

let is2Nil a b = 
  match a, b with
  | [], [] -> true
  | _, _ -> false

Array

https://ocaml.org/manual/5.2/api/Array.html

# let a = [|1; 2; 3; 4|];;
val a : int array = [|1; 2; 3; 4|]

sml vs ocaml

Analogues:

sml ocaml comment
structure module
signature module type
fn fun Anonymous functions
f o g -NA- Function composition
case match Pattern matching

Apparently, ocaml doesn't have a built-in compose function.

List elements are separated with ; in ocaml and , in sml

sml:

Standard ML of New Jersey (64-bit) v110.95 [built: Sat Feb 05 19:22:43 2022]
[1,2,3];;
val it = [1,2,3] : int list

OCaml:

OCaml version 4.14.1
Enter #help;; for help.

[1,2,3];;
- : (int * int * int) list = [(1, 2, 3)]

[1;2;3];;
- : int list = [1; 2; 3]

See: http://adam.chlipala.net/mlcomp/

Imperative features

From https://ocaml.org/docs/objects:

OCaml is an object-oriented, imperative, functional programming language. It mixes all these paradigms and lets you use the most appropriate (or most familiar) programming paradigm for the task at hand.

(Haskell is 'purer' than OCaml in the sense that there is lesser chance of side-effects.)

OOP (Object-oriented programming)

ocaml supports OOP-style classes: https://ocaml.org/docs/objects

Loops

https://ocaml.org/docs/if-statements-and-loops

ppx

Links:

[@@deriving _]

Tools

ocamlformat

An automatic code formatter.

dune integration (needs setup in dune-project):

dune

# Initialize new project
dune init proj <proj-name>

dune build
dune exec

References: https://ocaml.org/docs/up-and-running


Both of the following are equivalent??

dune exec -- <cmd>
dune install; <cmd>

opam

opam switches are comparable to python's venvs: https://ocaml.org/docs/opam-switch-introduction

Many useful packages are available only after adding this repo: opam repo add coq-released https://coq.inria.fr/opam/released

Reference: https://opam.ocaml.org/doc/Usage.html

tuareg mode of emacs

Can work with utop.

https://ocamlpro.github.io/ocaml-cheat-sheets/tuareg-mode.pdf


Tuareg: Emacs major mode for OCaml.

Insert template code snippet:

utop

https://www.systutorials.com/utop-key-bindings-key-shortcuts/

Misc

Packages

Jane Street libraries:

Historical:

Loading base (Jane Street)

base is a package from janestreet.

# #use "topfind";;
# #require "base";;
# open Base;;

base < corekernel < core

The extra # are needed.

Doubts

Infix operator as prefix

Enclose the operator within parenthesis.

Example:

utop # List.map (fun s -> "prefix " ^ s) l;;
- : string list = ["prefix hi"; "prefix hello"]

utop # List.map ((^) "prefix ") l;;
- : string list = ["prefix hi"; "prefix hello"]

utop # List.map (String.cat "prefix ") l;;
- : string list = ["prefix hi"; "prefix hello"]

utop # (^) ;;
- : string -> string -> string = <fun>

utop # (^) "a";;
- : string -> string = <fun>

Making an infix operator/function

Just put the name consisting of special characters and enclose it within parenthesis, I guess. https://stackoverflow.com/questions/38147841/how-to-define-an-infix-not-symbolic-aka-not-an-operator-function-in-ocaml

utop # let (+-) x y = x + y;;
val ( +- ) : int -> int -> int = <fun>

utop # 3 +- 4;;
- : int = 7

utop # let (a) x y = x + y;;
Error: Syntax error

if without else

This is possible if the then part value is of type unit.

fun x -> if x<3 then () ;;
- : int -> unit = <fun>

Otherwise, it would give error:

# fun x -> if x<3 then "hi" ;;
Error: This expression has type string but an expression was expected of type
         unit
       because it is in the result of a conditional with no else branch

Links:

Function vs value

This is a function:

let gethm () =
  let now = Unix.localtime (Unix.time ()) in
  let hour = now.tm_hour in
  let minute = now.tm_min in
  (hour, minute)

But this is a value:

let gethm =
  let now = Unix.localtime (Unix.time ()) in
  let hour = now.tm_hour in
  let minute = now.tm_min in
  (hour, minute)

OCaml 5

Effect handlers

No primitives for concurrency till Ocaml5.

Can think of effect handlers as 'first-class, restartable exceptions'

(* When [E] is performed, we will get a value of type [string] *)
effect E: string

(* A computation. Like a thunk *)
let comp () = 
  print_string "0: start";
  print_string (perform E);
  print_string "3: end";

let main () = 
  try
    comp ()
  (* Effect handler. [k] is a delimited continuation *)
  with effect E k ->
    print_string "1: EH start";
    continue k "2: EH cont";
    print_string "4: EH end";

Here control goes like:

Some errors

#load

Error: Reference to undefined global `Unix' Hint: This means that the interface of a module is loaded, but its implementation is not. Found home/famubu.opam/5.1.0/lib/ocaml/unix/unix.cma in the load paths. Did you mean to load it using #load "unix.cma" or by passing it as an argument to the toplevel?

let now = Unix.localtime (Unix.time ()) in let hour = now.tmhour in let minute = now.tmmin in (hour, minute);;

val gethm : int * int = (11, 25)

#+endsrc

Lack of information on exception

$ dune exec clock
2024-08-19 09:08:43.72231Z ERROR [thread=3] Process <0.5.0> died with unhandled exception Invalid_argument("index out of bounds"):

$ OCAMLRUNPARAM=b

$ dune exec clock
2024-08-19 09:09:35.34246Z ERROR [thread=0] Process <0.6.0> died with unhandled exception Invalid_argument("index out of bounds"):
Raised by primitive operation at Clock__Model.build_outstr in file "lib/model.ml", line 112, characters 8-24
Called from Minttea__Program.init in file "minttea/program.ml", line 49, characters 13-35
Called from Runtime__Import._spawn.(fun) in file "riot/runtime/import.ml", line 92, characters 10-15

Another example:

$ export OCAMLRUNPARAM=b
$ dune exec clock
2024-08-19 09:11:36.12397Z ERROR [thread=2] Process <0.6.0> died with unhandled exception Invalid_argument("index out of bounds"):
Raised by primitive operation at Clock__Model.build_outstr in file "lib/model.ml", line 79, characters 8-22
Called from Minttea__Program.init in file "minttea/program.ml", line 49, characters 13-35
Called from Runtime__Import._spawn.(fun) in file "riot/runtime/import.ml", line 92, characters 10-15

odoc

https://ocaml.github.io/odoc/

List: ul, ol

String formatting

Alignment:

Third party packages

Cmdliner

  1. Blocks

    Man page 'flags' provided by Cmdliner:

    `S section
    `P paragraph
    `I label-text paragraph
    `Pre pre-formatted text
    `Noblank suppress blank line between 2 blocks
    `Blocks list of (more) blocks

    From https://erratique.ch/software/cmdliner/doc/Cmdliner/Manpage/index.html

  2. 'Markup'

    • Italics: $(i, text)
    • Bold: $(b, text)

    https://erratique.ch/software/cmdliner/doc/tool_man.html#doclang

    • $(tname): term name (ie, command name?)
    • $(mname): main command name
    • $(iname)

    https://erratique.ch/software/cmdliner/doc/Cmdliner/Cmd/index.html#info

    • eval_ok: type for successful evaluation
    • eval_error: type for unsuccessful evaluation

    https://erratique.ch/software/cmdliner/doc/Cmdliner/Cmd/index.html#eval_low

  3. Term

    • const value: a Term that evaluates to value
    • ($) / app: function application with respect to Term

    Evaluate Term to get Result, which can be used to get an exit status.

  4. Env

  5. Cmd

    • val v : info -> 'a Term.t -> 'a t
      • v i t is a command with information i and command line syntax parsed by Cmd.t.

Hardcaml

  1. Operations

    https://github.com/janestreet/hardcaml/blob/master/docs/combinational_logic.md

    • Addition: Args must have same width, result will have that width
      • (+:): addition
      • (-:): subtraction
    • Multiplication: Args can be of different width, result will have sum of arg widths
      • (*:): unsigned multiplication
      • (*+): signed multiplication
    • (&:): logical and
    • (|:): logical or
    • (^:): logical xor
    • (:)~: logical not

    Vectors:

    • Splice: select v ~high:3 ~low:2 or v.:[3,2]
    • Concatenation: v1 @ v2