Download Object Oriented Programming with OCaml - Notes | CMSC 330 and more Assignments Programming Languages in PDF only on Docsity!
CMSC 330: Organization of
Programming Languages
Object Oriented Programming
with OCaml
CMSC 330 2
Reminders and Review
• Homework 2 was posted on Oct. 20
– Due on Oct. 30
• Project 3 due on Oct. 31
– Project 4 will be posted by then
• Midterm 2 on Nov. 1
• Closures
• Currying
CMSC 330 3
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 4
Data Types
• Rect and Circle are type constructors- here a
shape is either a Rect or a Circle
• Use pattern matching to deconstruct values, and
do different things depending on constructor
type shape = Rect of float * float (* width * length ) | Circle of float ( radius *)
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 7
Polymorphic Data Types
• This option type can work with any kind of data
– In fact, this option type is built-in to OCaml
type 'a option = None | Some of 'a
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
• Do you get the feeling we can build up lists this
way?
– Note: Don’t have nice [1; 2; 3] syntax for this kind of
list
type 'a list = Nil | Cons of 'a * 'a list
let rec length l = function Nil -> 0 | Cons (_, t) -> 1 + (length t)
length (Cons (10, Cons (20, Cons (30, Nil))))
CMSC 330 9
Data Type Representations
• Values in a data type are stored either directly
as integers or 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
• 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 13
Modularity and Abstraction
• Another reason for creating a module is so we
can hide details
– For example, we can build a binary tree module, but
we may not want to expose our exact representation
of binary trees
– This is also good software engineering practice
- Prevents clients from relying on details that may change
- Hides unimportant information
- Promotes local understanding (clients can’t inject arbitrary
data structures, only ones our functions create)
CMSC 330 14
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 *)
Entry in signature Supply function types
Give type to module
CMSC 330 15
Module Signatures (cont’d)
• The convention is for 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 16
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 19
Example
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 20
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 21
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
– Provides strong support for compositional reasoning
and abstraction
- Ex: Calling a function f with argument x always produces
the same result
CMSC 330 22
Imperative OCaml
• There are three basic operations on memory:
- ref : 'a -> 'a ref
- Allocate an updatable reference -! : 'a ref -> 'a
- Read the value stored in reference
- := : 'a ref -> 'a -> unit
let x = ref 3 (* x : int ref *) let y = !x x := 4
CMSC 330 25
Comparison to OCaml
• In OCaml, an updatable location and the
contents of the location have different types
– The location has a ref type
int x, y;
x = 3;
y = x;
3 = x;
let x = ref 0;; let y = ref 0;;
x := 3;; (* x : int ref *)
y := (!x);;
3 := x;; (* 3 : int; error *)
CMSC 330 26
Capturing a ref in a Closure
• We can use refs to make things like counters
that produce a fresh number “everywhere”
let next = let count = ref 0 in function () -> let temp = !count in count := (!count) + 1; temp;;
next ();;
next ();;
unit:
this is
how a
function
takes no
argument
CMSC 330 27
Semicolon Revisited; Side Effects
• Now that we can update memory, we have a
real use for ; and () : unit
– e1; e2 means evaluate e1, throw away the result, and
then evaluate e2, and return the value of e
– () means “no interesting result here”
– It’s only interesting to throw away values or use () if
computation does something besides return a result
• A side effect is a visible state change
– Modifying memory
– Printing to output
– Writing to disk
CMSC 330 28
Grouping with begin...end
• If you’re not sure about the scoping rules, use
begin...end to group together statements with
semicolons
let x = ref 0
let f () = begin print_string "hello"; x := (!x) + 1 end
CMSC 330 31
Exceptions (cont’d)
• 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, the current function exits
immediately and control transfers up the call chain
until the exception is caught, or until it reaches the
top level
CMSC 330 32
OCaml Language Choices
• Implicit or explicit declarations?
– Explicit – variables must be introduced with let before use
– But you don’t need to specify types
• Static or dynamic types?
– Static – but you don’t need to state types
– OCaml does type inference to figure out types for you
– Good: less work to write programs
– Bad: easier to make mistakes, harder to find errors