Type Systems determine what data is and how it's used
"true" is a string but true is a bool
We can't square strings and we can't add bool
Type Checking: The process of determining a variable's type
Dynamic typing: type checking is performed at run-time
Static typing: type checking is performed at compile-time
Manifest (explicit) typing: explicitly telling the compiler the type of new variables
Types are associated with variables
Latent (implicit) typing: not needing to give a type to a variable
Types are associated with values
Functional Programming: a programming paradigm based on functions
Programming Paradigm: classification of programming approach based behaviour of code
Programming Paradigm: classification of programming approach based behaviour of code
Features of functional languages
Program State: the state of the machine at any given time
Typically described as the contents of variables
# imperative.c
x = x + 1;
a[0] = 42;
Imperative: State is mutable, changing or destructive
Imperative: State is mutable, changing or destructive
Can cause side effects (which is bad)
# side_effects.java
int count = 0;
int f(Node node){
node.data = count;
count+=1;
return count;
}
No Referential transparency: replace expression with value with no side effects
f(x) + f(x) + f(x) != 3 * f(x) != 1 + 2 + 3
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 uses immutable state
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
Our First Ocaml Program
(* hello.ml *)
print_string "Hello World!\n"
OCaml is a compiled language
ocamlc hello.ml
Helpful Programs
Probably want to run dune utop src
Will need to use ;; to end epxressions in utop
Rememeber Syntax vs Semantics
Everything is an expression (e)
1 + 3
the expression 1+3 has type int
true
the value true has type bool
Expressions have types
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
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
(* 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
Function Calling Syntax
f x1 ... xn
Things that happen
(* factorial.ml *)
let rec fact n =
if n = 0 then
1
else
n * fact (n-1)
;;
fact 2;;
Type of f: int -> int
Type of f 2:int
Value of f 2: 2
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.ml *)
let x = e1 in e2
Let expressions are expressions
Expressions have a type
(* let-type.ml *)
(let x = e1:t1 in e2:t2):t2
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 are the basic data structure in OCaml
Lists are the basic data structure in OCaml
(* lists.ml *)
[1;2;3;4;5]
List Creation
(* lists-1.ml *)
e1::e2::[]
Lists are the basic data structure in OCaml
(* lists-1.ml *)
e1::e2::[]
Have type list
When evaluating, go right to left
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
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
Match looks at patterns of structure
Can be put as argument
(* match-function.ml *)
let car (h::_) = h;;
let cdr (_::t) = t;;
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 list *)
let rec sum lst = match lst with
[]-> 0
|h::t -> h + sum t;;
(* h has type int list *)
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? *)
Like Lists, but not really
(* tuples.ml *)
(1,2)
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 *)
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
Like a weird hash
(* records.ml *)
type data = { month: string; day: 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
We just saw this syntax
(* ud-types-alias.ml *)
type ilist = int list;;
let f x:ilist = [1;2;3;4];;
Ultimately not really useful in this form
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
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)
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
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)));;
Can be generic
(* some_none.ml *)
type 'a option =
Some of 'a
|None
Built into OCaml