Download OCaml Data Types and Modules: Building Custom Data Structures and Organizing Code and more Study notes Programming Languages in PDF only on Docsity!
CMSC 330: Organization of
Programming Languages
OCaml ā Data Types,
Exceptions, Modules,
CMSC 330 2
OCaml Data
So far, weāve seen the following kinds of data
- Basic types (int, float, char, string)
- Lists ¾ One kind of data structure ¾ A list is either [ ] or h::t, deconstructed with pattern matching
- Tuples ¾ Let you collect data together in fixed-size pieces
- Functions
How can we build other data structures?
- Building everything from lists and tuples is awkward
CMSC 330 3
Data Types
Rect and Circle are type constructors
- Here a shape is either a Rect or a Circle
type shape = Rect of float * float (* width * length ) | Circle of float ( radius *)
CMSC 330 4
Data Types (cont.)
Use pattern matching to deconstruct values
- s is a shape
- Do different things for s depending on its constructor
let area s = match s with Rect (w, l) -> w *. l | Circle r -> r *. r *. 3.
area (Rect (3.0, 4.0)) area (Circle 3.0)
CMSC 330 5
Data Types (cont.)
What's the type of l?
shape list
What's the type of l's first element?
shape
type shape = Rect of float * float (* width * length ) | Circle of float ( radius *)
let l = [Rect (3.0, 4.0) ; Circle 3.0]
CMSC 330 6
Data Types Constructor
Constructors must begin with uppercase letter
The arity of a constructor
- Is the number of arguments it takes
- A constructor with no arguments is nullary
Example
- Arity of None = 0
- Arity of Some = 1
type optional_int = None | Some of int
CMSC 330 7
Polymorphic Data Types
This option type can work with any kind of data
- In fact, this option type is built into OCaml
type optional_int = None | Some of int let add_with_default a = function None -> a + 42 | Some n -> a + n add_with_default 3 None (* 45 ) add_with_default 3 (Some 4) ( 7 *)
CMSC 330 8
Recursive Data Types
We can build up lists this way
- Wonāt have nice [1; 2; 3] syntax for this kind of list
type 'a list = Nil | Cons of 'a * 'a list
let rec len = function Nil -> 0 | Cons (_, t) -> 1 + (len t)
len (Cons (10, Cons (20, Cons (30, Nil))))
CMSC 330 9
Data Type Representations
Values in a data type are stored
- Directly as integers
- As pointers to blocks in the heap
type t = A of int | B | C of int * int | D
CMSC 330 10
Exercise: A Binary Tree Data Type
Write type bin_tree for binary trees over int
- Trees should be ordered (binary search tree)
Implement the following
empty : bin_tree is_empty : bin_tree -> bool member : int -> bin_tree -> bool insert : int -> bin_tree -> bin_tree remove: int -> bin_tree -> bin_tree equal : bin_tree -> bin_tree -> bool fold : (int -> 'a -> 'a) -> bin_tree -> 'a -> 'a
CMSC 330 11
OCaml Exceptions
exception My_exception of int let f n = if n > 0 then raise (My_exception n) else raise (Failure "foo") let bar n = try f n with My_exception n -> Printf.printf "Caught %d\n" n | Failure s -> Printf.printf "Caught %s\n" s CMSC 330 12
OCaml Exceptions (cont.)
Exceptions are declared with exception
- They may appear in the signature as well
Exceptions may take arguments
- Just like type constructors
- May also be nullary
Catch exceptions with try...with...
- Pattern-matching can be used in with
- If an exception is uncaught ¾ Current function exits immediately ¾ Control transfers up the call chain ¾ Until the exception is caught, or reaches the top level
CMSC 330 19
Module Signatures
module type FOO = sig val add : int -> int -> int end;; module Foo : FOO = struct let add x y = x + y let mult x y = x * y end;; Foo.add 3 4;; (* OK ) Foo.mult 3 4;; ( not accessible *)
Entry in signature (^) Supply function types
Give type to module
CMSC 330 20
Module Signatures (cont.)
Convention
- Signatures to be all capital letters
- This isn't a strict requirement, though
Items can be omitted from a module signature
- This provides the ability to hide values
The default signature for a module hides nothing
- Youāll notice this is what OCaml gives you if you just type in a module with no signature at the top-level
CMSC 330 21
Abstract Types in Signatures
Now definition of shape is hidden
module type SHAPES = sig type shape val area : shape -> float val unit_circle : shape val make_circle : float -> shape val make_rect : float -> float -> shape end;;
module Shapes : SHAPES = struct ... let make_circle r = Circle r let make_rect x y = Rect (x, y) end
CMSC 330 22
Abstract Types in Signatures
How does this compare to modularity in...
⢠C?
⢠C++?
Shapes.unit_circle
- : Shapes.shape = (* OCaml wonāt show impl *)
Shapes.Circle 1.
Unbound Constructor Shapes.Circle
Shapes.area (Shapes.make_circle 3.0)
open Shapes;;
(* doesnāt make anything abstract accessible *)
CMSC 330 23
.ml and .mli files
Put the signature in a foo.mli file, the struct in a
foo.ml file
- Use the same names
- Omit the sig...end and struct...end parts
- The OCaml compiler will make a Foo module from these
CMSC 330 24
Example ā OCaml Module Signatures
type shape val area : shape -> float val unit_circle : shape val make_circle : float -> shape val make_rect : float -> float -> shape
type shape = Rect of ... ... let make_circle r = Circle r let make_rect x y = Rect (x, y)
shapes.mli
shapes.ml
% ocamlc shapes.mli # produces shapes.cmi % ocamlc shapes.ml # produces shapes.cmo ocaml
#load "shapes.cmo" (* load Shapes module *)
CMSC 330 25
Functors
Modules can take other modules as arguments
- Such a module is called a functor
- Youāre mostly on your own if you want to use these
Example: Set in standard library
module type OrderedType = sig type t val compare : t -> t -> int end
module Make(Ord: OrderedType) = struct ... end
module StringSet = Set.Make(String);; (* works because String has type t, implements compare *) (^) CMSC 330 26
Module in Java
Java classes are like modules
- Provides implementations for a group of functions
- But classes can also ¾ Instantiate objects ¾ Inherit attributes from other classes
Java interfaces are like module signatures
- Defines a group of functions that may be used
- Implementation is hidden
CMSC 330 27
Module in C
.c files are like modules
- Provides implementations for a group of functions
.h files are like module signatures
- Defines a group of functions that may be used
- Implementation is hidden
Usage is not enforced by C language
- Can put C code in .h file
CMSC 330 28
Module in Ruby
Ruby explicitly supports modules
- Modules defined by module ⦠end
- Modules cannot ¾ Instantiate objects ¾ Derive subclasses
puts Math.sqrt(4) # 2 puts Math::PI # 3.
include Math # open Math puts Sqrt(4) # 2 puts PI # 3.
CMSC 330 29
So Far, Only Functional Programming
We havenāt given you any way so far to change
something in memory
- All you can do is create new values from old
This actually makes programming easier!
- Donāt care whether data is shared in memory ¾ Aliasing is irrelevant
- Provides strong support for compositional reasoning and abstraction ¾ Example: Calling a function f with argument x always produces the same result
- But could take (much) more memory & time to execute
CMSC 330 30
Imperative OCaml
There are three basic operations on memory
- ref : 'a -> 'a ref ¾ Allocate an updatable reference 2)! : 'a ref -> 'a ¾ Read the value stored in reference
- := : 'a ref -> 'a -> unit ¾ Write to a reference
let x = ref 3 (* x : int ref *) let y = !x x := 4
CMSC 330 37
The Trade-Off of Side Effects
Side effects are absolutely necessary
- Thatās usually why we run software!
- We want something to happen that we can observe
Butā¦they also make reasoning harder
- Order of evaluation now matters
- Calling the same function in different places may produce different results
- Aliasing is an issue ¾ If we call a function with refs r1 and r2, it might do strange things if r1 and r2 are aliased
CMSC 330 38
OCaml Language Choices
Implicit or explicit declarations?
- Explicit ā variables must be introduced with let before use
- But you donāt need to specify type of variable
Static or dynamic types?
- Static ā but without type declarations
- OCaml does type inference to figure out types for you ¾ Advantage ā less work to write programs ¾ Disadvantages ā easier to make mistakes, harder to find errors