tags : Functional Programming, Programming Languages
In the early ’80s, there was a schism in the ML community with the French on one side and the British and US on another. The French went on to develop CAML and later Objective CAML (OCaml) while the Brits and Americans developed Standard ML. The two dialects are quite similar. Microsoft introduced its own variant of OCaml called F# in 2005.
Intro
- Objective Categorical Abstract Machine language
- ML: Meta Language
Mutability
- OCaml is primarily an immutable language, like most functional languages.
- It does support imperative programming with mutable state, but we can probably not use it
Types
- Infer (Type checker will already do this)
- Annotate (Additional constraint for the type checker)
- Eg. (e:t): Parentheses are required for type annotation
 
- Eg. 
Building blocks
Syntax gotchas
- A design choice is made not to overload operators, eg. *and*.are different operators for ints and floats.
- If statements explicitly want boolean guards and branches need to be of same type
- use camelCasefor identifiers
- In ocaml we say, we applya function thancallit.
- Equality
- =and- <>examine structural equality whereas (This is what we want to use)
- ==and- !=examine physical equality.
 
- begin..endare equivalent to- ()
Functions
- Functions are
valuesand the body of the function is not evaluated unless applied.- Functions can be used as
arguments- Functions can be returned as
result
- 
Anonymous Function (Lambda expressions) - syntax: fun x1 ... xn -> e
- Eg. : fun x -> 42
 
- syntax: 
- 
Named - let poop x = x+1;
- let poop = fun x -> x+1;
 
- 
Recursive - let rec poop = poop;
- Mutually recursive functions can be written using and. 3110 book has a funny odd even example in Chapter2.4
 
- 
No multi argument functions - It might seem we can pass multiple arguments to ocaml, but that’s not what actually happens
- fun x y -> eis syntactic sugar for- fun x -> (fun y -> e)
- let add x y = x +yis syntactic sugar for- let add = fun x -> fun y -> x +y
 
- 
Polymporphic Functions  - Eg. let id x = x;;
- 'a: alpha (A type variable)
 
- Eg. 
Operators
- Defining infixbinary operators, we must wrap the operator in parens.- Eg. let ( <^> ) x y = max x y;;, whilelet <^> x y = max x y;;will give you errors. btw not using simply^because that’s the concat operator in ocaml.
 
- Eg. 
- To define infixoperators, you must surround them in parens
Semantic gotchas
Others
- Unitvalues: Eg.- assert eevaluates to a- unitvalue and nothing happens if- eis- true- For the Unittype, there’s only one value:()
- It’s usually using code that has side effects. Printing is an example of a side effect: it changes the world and can’t be undone.
- Special syntax that can be used to chain together multiple functions that return unit.
- The expression e1; e2first evaluatese1, which should evaluate to(), then discards that value, and evaluatese2.
- This can be used to chain multiple print statements together which usually evaluate to Unit.
 
- The expression 
 
- For the 
Value and Expression

Values
Do not need any further evaluation
Expressions

- Syntax rules
- Semantics
- Type checking rules
- Evaluation checking rules
 
- 
letexpression- This give a notion of scope
- Eg. let x = 2 in x(let expressions, we can use this inside other expressions)
- Here we’re binding a value to x
- Outside of this expression it’ll not be bound to xwhereas in case ofletdefinition, it’ll be bound to.
 
- 
nested letexpression w same variable name- let x = 5 in (let x = 6 in x)
- What this expression is evaluate to is the last x.
- In ocaml, things are not mutable. So, xwill not be redefined.
- Order is left to right
- let x = 5 in ...: Alright, x is assigned 5 for that scope
- let x = 6 in x: A new x is assigned here, and evaluated to- x
- xis returned. we get 6.(from the- innermost scope). i.e- let x = 5 in 6
- But we never used the older x. So the olderxremain unused.
- In other words, ocaml will not let us substitute the older value of xin the nested expression because it’ll violate Principle of Name Irrelevance
 
- It’s usually good not to mix the same variable name like this. You cannot get to the top level from the inner most level anyway for that x.
 
Definitions

let definition

- These are like variable
- These are NOT expressions, it does not have a value itself. (letexpression andletdefinition are different things)
- Eg. let x = 2(let definition)- This implicitly means, let x = 2 in "rest of what i type"
- When we do x=4;;x=7etc. we’re not mutatingx, we’re defining newxin a new scope. (So if you do this in ocaml toplevel/utop, you won’t be able to access previously definedxbut in files and programs we’ll be do so accordingly)
 
- This implicitly means, 
Builtin Data Types

Lists

- can be nilor wecons
- These are recursive and parameterized(takes any type) list
- #show list
- Operations
- Prepend
- Constant time O(1)
- 'a -> 'a list -> 'a list
- []~
- ::is used for construct objects in memory (- cons)
- ::is a binary constructor, takes- 'aand- 'a list
- ::is an infix constructor(the only one)
- 1st element is head, rest of the elements aretail
- []~
 
- Constant time 
- Appending
- Linear time O(n)
- 'a list -> 'a list -> 'a list
- [88] @ [77], this is not recommended in the hot path because lists are implemented as a singly linked list.
- The @is the append operator, not related to the apply operator
 
- Linear time 
 
- Prepend
Records

- with: Allows record copy. eg.- {poop with name = "something else"}. Does not allow you to add new fields as that would change the type of the record.
Tuple
type time = int * int * string
let t = (10, 10, "am")- Order is relevant
- fstand- sndlet you access tuple which are pairs
Features
Pattern Matching
match e with
| 2 -> e0
| p1 -> e1
| p2 -> e2
| pi -> ei
| _ -> 1
 
(* - p1, p2, p3 are patern variables so will be bound to e1, e2, e3 *)
(* - _ will not be bound *)- Can be used for matching with types, ints, strings, lists, records, tuples
- Pattern variables: Things that go after |afterwith
- What it allows
- Match is the shape of the data
- Extract/Transform parts of the data
 
- Typechecking
- eand- pineed to have same type
- Whole match would have type of ei. Alleineed to be of same type
 
Syntax Sugars
- For pattern matching with the last argument, we can use thefunctionkeyword. 
Pipeline operator
Pipeline (Reverse Application operator)
- succ (square (square (succ 3)));;
- v/s 5 |> succ |> square |> square |> succ;;
Custom Types
type primary = Red | Green | Blue
type 'a tree = Lf | Br of 'a * 'a tree * 'a tree;; (* here, 'a is type param/variable, tree is the name of the type *)Variants
- See Type Systems
- Value that could be one of several possibilities
- Each value is called a constructorand is separated with|(the use of word constructor is diff. from languages like c++)- constructorname must begin with Uppercase
- constructoris a- value
- contructorcan carry along optional data with it using the- ofkeyword
- contructioraka- tags
 
- Accessing variants can only happen via Pattern Matching
- constructorcan be constants or non-constants(which carry some value using- of)
- Variant Type
 
Options

- listand- optionare type constructors. They construct other types but are not types themsleves.- eg. int list,a' list,int optionand so on
 
- eg. 
- For options, we can use SomeandNoneforoption- I think SomeandNoneare variant walaconstructors
 
- I think 
- Syntax& Semantics
- Noneis a value of type- 'a option
- Some eis an expression of type- t optionif- e : t. If- e ==> vthen- Some e ==> Some v
 
Exceptions

Exception vs Options
- Exceptions make it easy to pipeline operations
Higher order functions
- Higher-order functions either take other functions as input or return other functions as output (or both).
- What differentiates this from things like function pointers in C is the idea of not having to pass the exta param of values of the variable to be used in the program. This is taken care of by the concept of closurein functional languages.
- About foldfold_left (+) 0 [1; 2; 3] <=> (((0 + 1) + 2 + 3) // zero is on the left fold_right (+) [1; 2; 3] 0 <=> 1 + (2 + (3 + 0))) // zero is on the right
Modularity
 

scope and open
let x = ListStack.peek (ListStack.push 42 ListStack.empty)
let x' = ListStack.(peek(push 42 empty))
let x'' = ListStack.(empty |> push 42 |> peek)
let x''' = let open ListStack in empty |> push 42 |> peek
(* Following is discouraged cuz pollute global scope *)
open ListStack
let v = empty |> push 42 |> peekSignatures
- These is sort of how we would implement interface
 

- Here Mtis asig
- This also provides encapsulation in the way that you can define functions which are not in the signature in the struct but if you try accessing those method from the moduledirectly, you’ll get a typechecking error
- In signature matching, it checks if the Modsuffices theSig. If the function inModcan take more than what Sig allows it’s okay, but it must atleast satisfySig. 
- Abstract Types
  - Usually denoted by t
- Constraintscan be added with things like- module type IntRing = Ring with type t = int- module type T = sig type t end module type U = T with type t = int
 
- Usually denoted by 
- We can sealaSigto a module using:module <NewSealedModName> : <SigName> = <UnsealedMod that Implements Sig>
- We can use includeto includesignature(declarations) orstructures(definitions)
Compilation Units
- DM : Definitions and Modules
- DS : Declarations and Signatures
 
include vs open

Functors

- Modulevalues are not like regular ocaml values. Most of the things like returning a module from a function etc will not work.
- But we have Functor, which is amodulelevel function. Input is a module, Output is a module.
- Type annotation is mandatory when writing a functor
Mutability
ref

Environment
Tooling
- opam : package manager
- ocamlopt : native code compiler
- ocamlc : bytecode compiler (less used)
- toplevel/utop
- When using #useexit and reload the toplevel if debugging, sometimes previous load overloads or something.
- -:in utop means it’s an anonymous definition
 
- When using 
Links and Resources
Books
- A Guided Tour - Real World OCaml
- OCaml from the Very Beginning
- http://courses.cms.caltech.edu/cs134/cs134b/book.pdf
Notes from 3110
TODO
- Skipping TDD: https://cs3110.github.io/textbook/chapters/data/ounit.html#test-driven-development
- Don’t understand: 5.7.2. Constraints
- Skipped: 5.6.6. Sets and Maps implementation
Scratch notes
utop # let pp = Fmt.Dump.list Fmt.int ;;
val pp : int list Fmt.t = <fun>
 
utop # Format.printf "%a" pp [1;2;3] ;;
[1; 2; 3]- : unit = ()pp above should be usable with ounit2. The printer type (Fmt.t which is Format.formatter -> ‘a -> unit) is very standard in OCaml, based on the stdlib Format module.