type variable = string;;

(* type 'a environment;; *)
type 'a environment (*= (variable * 'a) list*);; (* To do: make this an abstract type again *)

exception Unbound_variable of variable;;
exception Incompatible_environments of variable;;

val empty : 'a environment;;

val bind : variable -> 'a -> 'a environment -> 'a environment;;

val bind_many : (variable * 'a) list -> 'a environment -> 'a environment;;

val is_bound : variable -> ('a environment) -> bool;;

(* It may raise Unbound_variable *)
val lookup : variable -> 'a environment -> 'a;;

(* It may raise Incompatible_environments *)
val merge_disjoint : 'a environment -> 'a environment -> 'a environment;;

(* Bindings in the first parameter take precedence over the ones in the second parameter *)
val merge : 'a environment -> 'a environment -> 'a environment;;

(* This returns at most *one* binding per variable *)
val pairs_of_environment : 'a environment -> ((variable * 'a) list);;

(* In the given pairs, the first binding takes precedence over the others
   of the same variable. *)
val environment_of_pairs : ((variable * 'a) list) -> ('a environment);;

val extend : ('a environment) -> ('a environment) -> ('a environment);;
