CSCI 2041

ADVANCED PROGRAMMING PRINCIPLES

Modules, Polymorphism and Type Inference

Ocaml Programs

Expressions

A program is a sequence of expressions that are evaluated in order.

Every expression has a unique value and type.

We’ve seen primitive types and operators, let (rec) expressions, function values and types, and product types (tuples).

Ocaml has a language for specifying types: ->, *, 'a.

Structured data (tuples, lists) can be accessed through pattern matching.

The unit type

Ocaml has a built-in type, unit that has only one value, ().

What good is that?

To signal that a computation doesn’t result in a useful value:

val print_string : string -> unit

To signal that a function requires no input:

let compute_later () = x + y
compute_later ()

Such functions are often called thunks.

Multiple Files

Most interesting programs don’t fit in a single file.

In OCaml, we can refer to any name bound in file file.ml as File.name

How do we compile? Run ocamlc with all .ml files in order.

#mod_use to leave definitions in a module in utop

Type Inference

Example: searching a list for an element.

let rec search elt lst = match lst with
| [] -> false
| h::t -> if h=elt then true
          else search elt t

val search : 'a -> 'a list -> bool

How did Ocaml “know” the type of search?

The Ocaml compiler uses an algorithm to infer the type of every identifier.

Type inference rules

Initially, assign an identifier “most general type” 'a, 'b, ...'.

While checking the program, refine the type as needed:

  • Types of constants must match use
  • Functions must have type of the form t1 -> t2
  • Arguments to functions must match function input type
  • if ... then ... else must have matching branches
  • In the expression match v with p1 -> e1 | ... | p𝓃 -> e𝓃, v,p1,…p𝓃 must have matching types, and e1,…e𝓃 must have matching types
  • Every use of an identifier within its scope must have the same type

let id x = x

  • id : 'a
  • id : 'a -> 'b ; x : 'a
  • 'b = 'a (id returns x)
  • id : 'a -> 'a

let rec loopr x = loopr (x+1)

  • loopr : 'a
  • loopr : 'a -> 'b ; x : 'a
  • x : int ; 'a = int (x is passed as an argument to +)
  • loopr : int -> 'b
let rec exp = function (_,0) -> 1.0  
| (b,n) -> b *. (exp (b,n-1))
  • exp : 'a
  • exp : 'a -> 'b (due to function keyword)
  • 'a = 'c * int (due to (_,0) pattern)
  • 'b = float' (due to body of 1st clause, 1.0 : float)
  • b : 'c ; n : int (in 2nd clause pattern)
  • b : float ; 'c = float (b passed as argument to *.)
  • val exp : float * int -> float
let rec search elt lst = match lst with
| [] -> false
| h::t -> if h=elt then true
          else search elt t
  • search : 'a

  • search : 'a -> 'b -> 'c ; elt : 'a ; lst : 'b

    (search = fun elt -> fun lst ->...)

  • lst : 'd list ; 'b = 'd list (due to [] in 1st pattern)

  • 'c = bool (due to body of 1st clause : false : bool)

  • h : 'd ; t : 'd list (second pattern)

  • 'd = 'a (h and elt are passed to (=) : 'a -> 'a -> bool)

  • val search : 'a -> 'a list -> bool

Finding a type error…

let rec search1 elt lst = match lst with
| [] -> []
| h::t -> (h=elt) || (search1 elt t)
  • search1 : 'a -> 'b -> 'c ; elt : 'a ; lst : 'b

  • lst : 'd list ; 'b = 'd list

  • 'c = 'e list (body of first clause)

  • h : 'd; t : 'd list

  • 'e list = bool (result (search1 elt t) used as argument to ||)

    Error: this expression has type 'a list but an expression of type bool was expected

cs2041.org

// reveal.js plugins