Article

OCaml学习

记录学习OCaml的过程中的知识点.

  • Notes
  • Computer
dune build --watch

Ocaml中的表达式

value: an expression for which there is no computation to be performed

Primary Task of Computation : evaluate an expression to a value

Fail to evaluate an expression to a value: (1) => raises an exception (2) => infinite loop

int: ocaml Integers ranges from $-2^{62} \sim 2^{62} - 1$, 1 bit is used at run time to distinguish integers from pointers (garbage collector)

float : 3. / 3.0 / 3.14

operations between float 3. *. 2.

bool : true / false

char: ‘a’, ‘b’, ‘c’… (represented as bytes, i.e. 8-bit integers)

string: sequence of chars (concat “abc” ^ “def”). (string_to_int, string_to_float, string_to_bool …) no string_to_char but have String.make

no char_to_string but have “aes”.[1]

’=’ and ’<>’ examine structural equality ’==’ and ’!=’ examine physical equality

assert e => evaluate e, if true, the res of assert e is a special value called ’()’, type ‘unit’


evaluation rules: define how to evaluate expressions typing rules: describes how to type check an expression.

e(metavariable) has type t(metavariable) <=> e : t


let x = 42 # definition let x = 42 in x # expression, bind 42 to x and use it in x expression

let a = 42;; <=> let a = 42 in

alpha equivalence : the two funcs are equivalent up to renaming of variables.

![[Pasted image 20260817192402.png]]

let f x = … (definition of func) let rec f x = … (definition of recursive func)

mutually recursive func:

let rec f x1 ... xn = e1
and g y1 ... yn = e2

anonymous functions(lambda functions)

useful in higher-order programming

keyword fun

let inc = func x -> x + 1

lambda calculus


(func x -> e1) e2

and

let x = e1 in e2

they are syntactically different but semantically equivalent


Pipeline 一种内置的特殊中缀运算符

5 |> inc |> square

Polymorphic functions

let id x = x

type of id is 'a -> 'a

let id_int : int -> int = id

这个是把一个'a -> 'a类型的表达式赋值给了一个'int -> 'int类型的表达式, 可以这么考虑这件事, 'int -> 'int只是'a -> 'a 所有可能的行为中的一种, 只是其他的可能行为被丢掉了.


labeled and optional arguments

(**labeled arguments**)
let f ~name1:(arg1 : int) ~name2:(arg2 : int) = arg1 + arg2
let f ~name1 ~name2 = name1 + name2
(**optional arguments**)
let f ?name1:(arg1=8) name2(arg2) = arg1 + arg2

Partial Application

let add x y = x + y
let addx x = fun y -> x + y
let add = fun x -> (fun y -> x + y)

Every OCaml function takes exactly one argument

function types are right associative

function application is left associative

f : X -> (Y -> Z)
f x y z <=> (((f x) y) z)

Define our own infix operator

let ( ^^ ) x y = max x y
2 ^^ 3

Tail Recursion

let rec count_n n = if n = 0 then 0 else 1 + count_n (n - 1)

this will run out of memory of stack space when n is large

Tail Recursion Optimization

let rec count_aux n acc = if n = 0 then acc else count_aux (n - 1) (acc + 1)
let count_tr n = count_aux n 0

Why tail position matters: A recursive call in tail position does not need a new stack frame. (No computation left to be done.)

compiler should support tail recursive Optimization (Java not support)

example:

let rec fact n = if n = 0 then 1 else n * fact (n - 1)

tr version

let rec fact_helper n acc = if n = 0 then acc else fact_helper (n - 1) (n * acc)
let fact_tr n = fact_helper n 1

Zarith OCaml’s big integer lib


** -> comment to be recognized as an OCamldoc comment

() -> be rendered in HTML as typewriter font


side effect -> changes the world and can’t be undone


print_endline "are";

e1 ; e2 -> evaluates e1, then discard that value, and evaluates e2

ignore ‘a -> unit


Debugging

How to discovered bugs

  1. Memory Safety and Type Safety language

  2. Use tools to find bugs

  3. Fail fast

  4. Write automated code tests

After discovered bugs

  1. Distill the bug into a small test case

  2. Employ the scientific method

  3. Fix the bug

  4. Add the small test case from step 1 in test suite

Debugging in OCaml

  1. Print statement
let inc x =
  let () = print_endline x in
  x + 1

这个作为一个整体是一个definition, 然后let () = print_endline x in x + 1是一个expression

Function traces

let rec fib x = if x <= 1 then 1 else fib (x - 1) + fib (x - 2)
#trace fib;;

use #untrace to stop trace func

Defensive Programming

let random_int bound =
  if not (bound > 0 && bound < 1 lsl 30)
    then invalid_arg "bound";

to be continued...