Exercises
Association Lists
In this first simple exercise, we will implement a polymorphic
abstract type for association lists, and present two different views
of the implementation.
- Define a signature ALIST
declaring an abstract type with two type parameters (one for the keys,
the other for the associated values), a creation function, an add
function, a lookup function, a membership test, and a deletion
function.
module
type
ALIST
=
sig
type
('a,
'b)
t
val
create
:
unit
->
('a,
'b)
t
val
add
:
'a
->
'b
->
('a,
'b)
t
->
('a,
'b)
t
val
get
:
'a
->
('a,
'b)
t
->
'b
val
mem
:
'a
->
('a,
'b)
t
->
bool
val
rem
:
'a
->
('a,
'b)
t
->
('a,
'b)
t
end
;;
Characters 142-148:
Syntax error
The interface should be functional, i.e. without in-place modifications of the abstract type.
- Define a module Alist implementing the
signature ALIST
# module
Alist:
ALIST
=
struct
type
('a,
'b)
t
=
('a*
'b)
list
let
create
()
=
[]
let
add
k
v
al
=
(k,
v)::al
let
get
=
List.assoc
let
mem
=
List.mem_assoc
let
rem
=
List.remove_assoc
end
;;
Characters 14-19:
Unbound module type ALIST
- Define a signature ADM_ALIST
for ``administrators'' of association lists. Administrators can only
create association lists, and add or remove entries from a list.
# module
type
ADM_ALIST
=
sig
type
('a,
'b)
t
val
create
:
unit
->
('a,
'b)
t
val
add
:
'a
->
'b
->
('a,
'b)
t
->
('a,
'b)
t
val
rem
:
'a
->
('a,
'b)
t
->
('a,
'b)
t
end
;;
module type ADM_ALIST =
sig
type ('a, 'b) t
val create : unit -> ('a, 'b) t
val add : 'a -> 'b -> ('a, 'b) t -> ('a, 'b) t
val rem : 'a -> ('a, 'b) t -> ('a, 'b) t
end
- Define a signature USER_ALIST
for ``users'' of association lists. Users can only perform lookups
and membership tests.
# module
type
USER_ALIST
=
sig
type
('a,
'b)
t
val
get
:
'a
->
('a,
'b)
t
->
'b
val
mem
:
'a
->
('a,
'b)
t
->
bool
end
;;
module type USER_ALIST =
sig
type ('a, 'b) t
val get : 'a -> ('a, 'b) t -> 'b
val mem : 'a -> ('a, 'b) t -> bool
end
- Define two modules AdmAlist and UserAlist
for administrators and for users. Keep in mind that users must be
able to access lists created by administrators.
# module
AdmAlist
=
(Alist:
ADM_ALIST
with
type
('a,
'b)
t
=
('a,
'b)
Alist.t)
;;
Characters 20-25:
Unbound module Alist
# module
UserAlist
=
(Alist:
USER_ALIST
with
type
('a,
'b)
t
=
('a,
'b)
Alist.t)
;;
Characters 20-25:
Unbound module Alist
Parameterized Vectors
This exercise illustrates the genericity and code reuse abilities of
parameterized modules. We will define a functor for manipulating
two-dimensional vectors (pairs of (x,y) coordinates) that can be
instantiated with different types for the coordinates.
Numbers have the following signature:
# module
type
NUMBER
=
sig
type
a
type
t
val
create
:
a
->
t
val
add
:
t
->
t
->
t
val
string_of
:
t
->
string
end
;;
-
Define the functor FVector,
parameterized by a module of signature NUMBER,
and defining a type t of two-dimensional vectors over these numbers,
a creation function, an addition function, and a conversion to strings.
# module
FVector
(N:
NUMBER)
=
struct
type
e
=
N.t
type
t
=
{
mutable
vx:
e;
mutable
vy:
e
}
let
create
x0
y0
=
{
vx=
x0;
vy=
y0
}
let
add
v1
v2=
{vx
=
N.add
v1.
vx
v2.
vx;
vy
=
N.add
v1.
vy
v2.
vy}
let
string_of
v=
"("
^
N.string_of
v.
vx^
" , "
^
N.string_of
v.
vy^
")"
end
;;
module FVector :
functor(N : NUMBER) ->
sig
type e = N.t
and t = { mutable vx: e; mutable vy: e }
val create : e -> e -> t
val add : t -> t -> t
val string_of : t -> string
end
- Define a signature VECTOR,
without parameters, where the types of numbers and vectors are abstract.
# module
type
VECTOR
=
sig
type
e
type
t
val
create
:
e
->
e
->
t
val
add
:
t
->
t
->
t
val
string_of
:
t
->
string
end
;;
module type VECTOR =
sig
type e
and t
val create : e -> e -> t
val add : t -> t -> t
val string_of : t -> string
end
- Define three structures Rational,
Float et Complex implementing the signature
NUMBER.
# module
Rational:
NUMBER
=
struct
type
a
=
int*
int
type
t
=
{
p:
int;
q:
int
}
let
create
(p0,
q0)
=
{
p=
p0;
q=
q0
}
let
add
r1
r2
=
{
p
=
r1.
p*
r2.
q
+
r2.
p*
r1.
q;
q
=
r1.
q*
r2.
q
}
let
string_of
r
=
(string_of_int
r.
p)^
"/"
^
(string_of_int
r.
q)
end
;;
module Rational : NUMBER
# module
Float:
NUMBER
=
struct
type
a
=
float
type
t
=
a
let
create
x
=
x
let
add
=
(+.
)
let
string_of
=
string_of_float
end
;;
module Float : NUMBER
# module
Complex:
NUMBER
=
struct
type
a
=
float*
float
type
t
=
{
r:
float;
i:
float
}
let
create
(r0,
i0)
=
{
r=
r0;
i=
i0
}
let
add
c1
c2
=
{
r
=
c1.
r+.
c2.
r;
i
=
c1.
i+.
c2.
i
}
let
string_of
c
=
(string_of_float
c.
r)^
"+"
^
(string_of_float
c.
r)^
"*i"
end
;;
module Complex : NUMBER
- Use these structures to define (by functor application)
three modules for vectors of rationals, reals
and complex.
# module
RatVect:
VECTOR
=
FVector(Rational)
;;
module RatVect : VECTOR
# module
FloVect:
VECTOR
=
FVector(Float)
;;
module FloVect : VECTOR
# module
ComVect:
VECTOR
=
FVector(Complex)
;;
module ComVect : VECTOR
Lexical Trees
This exercise follows up on the lexical trees introduced in
chapter 2, page ??. The goal is to
define a generic module for handling lexical trees, parameterized by
an abstract type of words.
-
Define the signature WORD defining
an abstract type alpha for letters of the alphabet,
and another abstract type t for words on this alphabet.
Declare also the empty word, the conversion from an alphabet letter to
a one-letter word, the accessor to a letter of a word, the sub-word
operation, the length of a word, and word concatenation.
# module
type
WORD
=
sig
type
alpha
type
t
val
null
:
t
val
of_alpha
:
alpha
->
t
val
get
:
t
->
int
->
alpha
val
sub
:
t
->
int
->
int
->
t
val
length
:
t
->
int
val
concat
:
t
->
t
->
t
end
;;
module type WORD =
sig
type alpha
and t
val null : t
val of_alpha : alpha -> t
val get : t -> int -> alpha
val sub : t -> int -> int -> t
val length : t -> int
val concat : t -> t -> t
end
- Define the functor LexTree,
parameterized by a module implementing WORD, that defines
(as a function of the types and operations over words) the type of
lexical trees and functions exists, insert et
select similar to those from chapter 2, page
??.
# module
LexTree
(W:
WORD)
=
struct
type
node
=
Letter
of
W.alpha
*
bool
*
t
and
t
=
node
list
let
rec
exist
m
d
=
let
aux
sm
i
n
=
match
d
with
[]
->
false
|
(Letter
(a,
b,
l))::q
when
a
=
W.get
sm
i
->
if
n
=
1
then
b
else
exist
(W.sub
sm
(i+
1
)
(n-
1
))
l
|
(Letter
(a,
b,
l))::q
when
a
=
W.get
sm
i
->
exist
sm
q
in
aux
m
0
(W.length
m)
let
rec
insert
m
d
=
let
aux
sm
i
n
=
if
n
=
0
then
d
else
match
d
with
[]
->
let
aux
=
insert
(W.sub
sm
(i+
1
)
(n-
1
))
[]
in
[
Letter
(W.get
sm
i,
n
=
1
,
aux)
]
|
(Letter(a,
b,
l))::q
when
a
=
W.get
sm
i
->
if
n
=
1
then
(Letter(a,
true,
l))::q
else
Letter(a,
b,
add
(W.sub
sm
(i+
1
)
(n-
1
))
l)::q
|
(Letter(a,
b,
l))::q
->
(Letter(a,
b,
l))::(ajoute
sm
q)
in
aux
m
0
(W.length
m)
let
rec
select
n
d
=
match
d
with
[]
->
[]
|
(Letter(a,
b,
l))::q
when
n=
1
->
let
f
(Letter(a,
b,_
))
=
if
b
then
W.of_alpha
a
else
W.null
in
List.filter
((<>
)
W.null)
(List.map
f
d)
|
(Letter(a,
b,
l))::q
->
let
r
=
select
(n-
1
)
l
and
r2
=
select
n
q
in
let
pr
=
List.map
(function
s
->
W.concat
(W.of_alpha
a)
s)
r
in
pr@
r2
end
;;
Characters 161-407:
Warning: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
_::_
Characters 853-854:
This expression has type t = node list but is here used with type W.t dlist
- Define the module Chars implementing the WORD
signature for the types alpha = char and t = string.
Use it to obtain a module CharDict
implementing dictionaries whose keys are character strings.
# module
Chars
=
struct
type
alpha
=
char
type
t
=
string
let
null
=
""
let
of_alpha
c
=
String.make
1
c
let
get
s
i
=
try
s.[
i]
with
Invalid_argument(_
)
->
raise
(Invalid_argument
"Chars.get"
)
let
sub
s
i1
i2
=
try
String.sub
s
i1
i2
with
Invalid_argument(_
)
->
raise
(Invalid_argument
"Chars.sub"
)
let
length
=
String.length
let
concat
=
(^
)
end
;;
module Chars :
sig
type alpha = char
and t = string
val null : string
val of_alpha : char -> string
val get : string -> int -> char
val sub : string -> int -> int -> string
val length : string -> int
val concat : string -> string -> string
end
# module
CharsDic
=
LexTree(Chars)
;;
Characters 19-26:
Unbound module LexTree