CMSC330

Ocaml Data Types

OCaml Data Types

Declarative Programming
Lets
Lists and Pattern Matching
Data Types

Declarative Programming

A way of expressing a program's purpose

Don't really care how

Consider the iterative:


(* iterative.rb *)
arr = [1,2,3]
res = []
for i in arr
  if i % 2 == 0 
    res.push(i)
  end
end
res
          

Tells you what to do

Series of steps to achieve your goal

Consider the declarative:


(* declare.rb *)
arr = [1,2,3] in
arr.filter{|x| x%2==0}
          

Tells you what you want

Does not care how, just the end result

Focus on what you want, and don't worry about the specifics

Focus on what you want, and don't worry about the specifics

Function: input to output

Combine functions to get what you want

Either recursively or combination of functions

Let expressions

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

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 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 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

Pattern Matchitng

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

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

Pattern Matching

Match looks at patterns of structure

Can be put as argument


(* match-function.ml *)
let car (h::_) = h;;
let cdr (_::t) = t;;
          
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 *)
          
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
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 *)
          
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
          
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
          
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

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