 
 
 
 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
 
 
 
 
