CMSC330

Ocaml

OCaml

Functional Programming
Ocaml Env
Functions and Expressions
Lets
Lists and Pattern Matching
Data Types

Functional Programming

Functional Programming: a programming paradigm based on functions

Programming Paradigm: classification of programming approach based behaviour of code

Functional Programming

Programming Paradigm: classification of programming approach based behaviour of code

  • Typically used interchangibly with language features

  • Python is imperative, object-oriented, and technically functional

  • OCaml is imperative, object-oriented and functional

Functional Programming

Features of functional languages

  • Immutable State

  • Declarative Programming

  • Referential transparency

  • Realistic about the Machine

Functional Programming

Program State: the state of the machine at any given time

Typically described as the contents of variables


# imperative.py
x = x + 1
a[0] = 42
          

Imperative: State is mutable, changing or destructive

Functional Programming

Imperative: State is mutable, changing or destructive

Can cause side effects (which is bad)


# side_effects.py
count = 0
def f(node)
  global count
  node.data = count
  count+=1
  return count
end
          

No Referential transparency: replace expression with value with no side effects


f(x) + f(x) + f(x) != 3 * f(x) != 1 + 2 + 3
          

Functional Programming

Imperative: State is mutable, changing or destructive

Reality Check: No single state exists


# states.c
int x = 1;
if (fork() == 0)
  x = x + 1;
else
  x = x * 5;
wait(NULL)
printf("x: %d\n", x);
          

Functional Programming has immutable state

Functional Programming

Functional Programming uses immutable state

  • Will minimize side effects

  • Assumes referential transparency

  • Builds Correct Programs

Functional Programming

Declarative Programming


# imperative.py
def evens(arr):
  ret  = []
  for x in arr
    remainder = x % 2
    if remainder == 0:
      ret.append(x)
  return ret
          

as opposed to


declarative.py
def evens(arr):
  ret = [x for x in arr if x % 2 == 0]
  return ret
          

OCaml Env

Our First Ocaml Program


  (* hello.ml *)
  print_string "Hello World!\n"
            
  • No semi colon (for now)
  • (* *) for comment

OCaml is a compiled language


  ocamlc hello.ml
            
  • a.out: executable
  • hello.cmocompiled object (.o)
  • hello.cmicompiled interface (like .h)

OCaml Env

Helpful Programs

  • ocaml: repl like python
  • utop: like ocaml but better
  • dune like Make
  • opam package manager for OCaml

Probably want to run dune utop src

Will need to use ;; to end epxressions in utop

Functions and Expressions

Rememeber Syntax vs Semantics

Everything is an expression (e)

  • Expressions evaluate to values (v)
  • All values are expressions, but not vice versa
  • Expressions have types (t)
  • e: t will mean expression e has type t

Functions and Expressions


1 + 3
          

the expression 1+3 has type int


true
          

the value true has type bool

Expressions have types

Functions and Expressions

Expressions have types

The if expression


(if e1:bool then e2:t else e3:t):t
          

Actual Syntax:


if e1 then e2 else e3
          

Static and Latent Typing

Functions and Expressions

Expressions have types

functions are expressions


(* function.ml *)
let f x = 
  if x mod 2 = 0 then
    1
  else
    0
in f
;;
          

The expression f has type int->int

Type Inference: inferring a variable's type

Functions and Expressions


(* function.ml *)
let f x = 
  if x mod 2 = 0 then
    1
  else
    0
in f
;;
          

Function Definition Syntax

let f x1 ... xn = e

Function Calling Syntax

f x1 ... xn

Functions and Expressions

Function Calling Syntax

f x1 ... xn

Things that happen

  • Each argument x is evaluated to a value v
  • Substitute all x in e with v
  • Call the new expression e'
  • Evaluate e' to value v'

Functions and Expressions


(* factorial.ml *)
let rec f n = 
  if n = 0 then
    1
  else
    n * fact (n-1)
in f
;;
f 2;;
          

Type of f: int -> int

Type of f 2:int

Value of f 2: 2

Functions and Expressions

More on Type Checking

Types are inferred by operations they use


(* types.ml *)
(* compare two same types *)
1 = 1
x = y
x > y
x < y
(* x and y must have the same type *)

(* int have operators *)
3 + 4
x - y
x * y
x / y
x mod y

(* floats have different ones *)
3.2 +. 4.
x -. y
x *. y
x /. y

(* Strings have some too*)
"hello" ^ " world"

(* latent typing means inference *)
let f x y = if x > y then x else y-4;;
(* int -> int -> int *)
          

Let expressions


(* let.ml *)
let x = e1 in e2
          
  • Let expressions are not the same as let definitions
  • Bind local variables for e2
  • Scope is only for the body

Let expressions are expressions

Expressions have a type


(* let-type.ml *)
(let x = e1:t1 in e2:t2):t2
          

Let expressions

Let Expressions

Can be nested


(* let-nest.ml *)
let x = 3 in let y = 4 in x + y
          

Can be used for local variables


(* let-vars.ml *)
let area r = 
  let pi = 3.14 in
  pi *. r *. r
          

Variables will be shadowed


(* let-shadowing.ml *)
let x = 3 in let x = 5 in x + 4
          

Lists and Pattern Matching

Lists are the basic data structure in OCaml

  • Arbitrary Length
  • Homogenous
  • Implemented as a Linked List
  • Can be constructed and deconstructed

Lists and Pattern Matching

Lists are the basic data structure in OCaml


(* lists.ml *)
[1;2;3;4;5]
          
  • ; as seperator
  • Bracket Syntax
  • No indexing

List Creation


(* lists-1.ml *)
e1::e2::[]
          

Lists and Pattern Matching

Lists are the basic data structure in OCaml


(* lists-1.ml *)
e1::e2::[]
          
  • []- empty list (nil)
  • ::- cons
  • A list has a Head and Tail

Have type list

When evaluating, go right to left

Lists and Pattern Matching

Can deconstruct lists


(* match-nest.ml *)
let x = [1;2;3] in match x with
|[] -> true
|h::t -> false
          

Match looks at patterns of structure

Lists and Pattern Matching

Match looks at patterns of structure

Common Patterns


(* match-patterns.ml *)
let empty x = in match x with
|[] -> true (* empty *)
|a::[] -> false (* list of size 1 *)
|h::t -> false (* list at least size 1 *)
|_ -> false (* wildcard *)
          

Variables are bound on order

Last item is a list

Lists and Pattern Matching

Match looks at patterns of structure

Can be put as argument


(* match-function.ml *)
let car (h::_) = h;;
let cdr (_::t) = t;;
          

Lists and Pattern Matching

Match looks at patterns of structure

Can be Polymorphic


(* match-polymorphic.ml *)
let car lst = match lst with 
[] -> []
h::_ -> h;;
(* lst has type 'a list *)

let rec sum lst = match lst with
[]-> 0
|h::t -> h + sum t;;
(* h has type int list *)
          

Lists and Pattern Matching

Used commonly in recursive functions


(* match-rec-functions.ml *)
let rec sum lst = match lst with
[]-> 0
|h::t -> h + sum t;;

let rec negate lst = match lst with
[]-> []
|h::t -> -h + negate t;;

let rec last lst = match lst with
[x]-> x
|h::t -> last t;;

let rec append l m = match l with
[]-> m
|h::t -> x :: (append t m)

let rec rev l = match l with
|[] -> []
| h::t -> append (rev t) (h::[])
(* rev is O(n^2) *)
(* can you do better? *)
          

Data Types

Tuples

Like Lists, but not really


(* tuples.ml *)
(1,2)
          
  • Surrounded with ()
  • Seperated with ,
  • Heterogenous
  • Fixed size

Data Types

Tuples

Tuples have a set Type


(* tuples-type.ml *)
(1,2) (* int * int *)
(1,"string",2.3) (* int * string * float *)
('a','b') (* char * char *)
['a';'b'] (* char list *)
[(1,2);(3,4)] (* (int * int) list *)
([1;2],[3;4]) (* int list * int list *)
          

Data Types

Tuples

Can Pattern Match


(* tuples-match.ml *)
let add t = match t with
(a,b) -> a + b
          

Remember Tuples have a type based on size


(* tuples-match-err.ml *)
let add t = match t with
(a,b) -> a + b
|(a,b,c) -> a + b + c
          

Data Types

Records

Like a weird hash


(* records.ml *)
type data = { month: string; dat: int; year: int };;
let today = { day=29; year=2020; month="feb"};;
          

O in OCaml stands for Object


(* record-access-1.ml *)
print_string today.month
          

Can also pattern match


(* record-access-2.ml *)
let { month=_; day = d} = today in
print_int d
          

Data Types

User Defined Types

We just saw this syntax


(* ud-types-alias.ml *)
type ilist = int list;;
let f x:ilist = [1;2;3;4];;
          
  • Like a typedef
  • type keyword will allow for an alias

    Ultimately not really useful in this form

Data Types

Variant Types are more useful


(* ud-variants.ml *)
type parity = Even | Odd 
          

Like an enum


(* pm-variants.ml *)
let swap x = match x with
Even -> Odd
|Odd -> Even
          

    Can be Pattern Matched

Data Types

Can Hold Data


(* ud-variants-1.ml *)
type parity = Even of int | Odd of int
          

Can still be Pattern Matched


(* pm-variants-1.ml *)
let add x = match x with
Even(x) -> Odd(x+1)
|Odd(x) -> Even(x+1)
          

Data Types

Can Hold Data

Can be different


(* ud-variants-2.ml *)
type shape = Rect of int * int | Circle of float 
          

Can still be Pattern Matched


(* pm-variants-2.ml *)
let area s = match s with
Rect (w,l) -> float_of_int (w*l)
|Circle r  -> r *. r *. 3.14
          

Data Types

Can be Recursive


(* llist.ml *)
type linked = 
Item of string * linked
|Null;;

let head lst = match lst with
Item(x,_) -> x
|Null -> "";;

head (Item("Hello",Item("world", Null)));;
          

Data Types

Can be generic


(* some_none.ml *)
type 'a option = 
Some of 'a
|None
          

Built into OCaml