OCaml Data Types and Modules: Building Custom Data Structures and Organizing Code, Study notes of Programming Languages

An excerpt from a computer science course on the organization of programming languages using ocaml. It covers the concepts of data types, including rectangles and circles, and the use of pattern matching for deconstruction. The document also introduces the concept of module construction and the benefits of modular programming. Students will learn how to build custom data structures and organize their code for better software engineering practices.

Typology: Study notes

Pre 2010

Uploaded on 02/13/2009

koofers-user-8b1-1
koofers-user-8b1-1 šŸ‡ŗšŸ‡ø

9 documents

1 / 7

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
1
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
•sis a shape
•Do different things for sdepending on its constructor
let area s =
match s with
Rect (w, l) -> w *. l
| Circle r -> r *. r *. 3.14
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
pf3
pf4
pf5

Partial preview of the text

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

  1. Directly as integers
  2. 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++?
  • Java?

Shapes.unit_circle

  • : Shapes.shape = (* OCaml won’t show impl *)

Shapes.Circle 1.

Unbound Constructor Shapes.Circle

Shapes.area (Shapes.make_circle 3.0)

  • : float = 29.

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

  1. ref : 'a -> 'a ref ¾ Allocate an updatable reference 2)! : 'a ref -> 'a ¾ Read the value stored in reference
  2. := : '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