Avoiding many small structs
That is not entirely uncommon, especially for instantiating
data-structure functors. If you are reusing the same structure for
multiple functors, then it often makes sense to give it an ********
name. But, two useful features of the SML module system are
"anonymous" structures and signature matching.
I don't have Okasaki's book handy, but suppose there was a functor
functor BinomialQueue (E : ORDERED): PRIORITY_QUEUE = struct ... end
Then, each of the following is equivalent
structure RBQ1 = BinomialQueue(OrderedReal)
structure RBQ2 = BinomialQueue(open OrderedReal)
structure RBQ3 =
BinomialQueue(struct
type t = Real.real
val eq = Real.==
val lt = Real.<
val leq = Real.<=
end)
structure RBQ4 =
BinomialQueue(type t = Real.real
val eq = Real.==
val lt = Real.<
val leq = Real.<=)
You can see that the instantiations for RBQ3 and RBQ4 do not require
an ******** name for the structure passed to the functor.
If the functor argument chooses names that (mostly) match those
available in the Standard Basis, then it can be a win to take
advantage of signature matching, which will allow you to instantiate
the functor with a structure that contains a superset of the necessary
arguments. For example, if the ORDERED signature were given by
signature ORDERED =
sig type t
val compare : t * t -> order
val max : t * t -> t
val min : t * t -> t
end
then each of the following would be equivalent:
structure OrderedReal =
struct
type t = real
val compare = Real.comare
val max = Real.max
val min = Real.min
end
structure RBQ1 = BinomialQueue(OrderedReal)
structure RBQ2 = BinomialQueue(open OrderedReal)
structure RBQ3 =
BinomialQueue(struct
type t = real
val compare = Real.comare
val max = Real.max
val min = Real.min
end)
structure RBQ4 =
BinomialQueue(type t = real
val compare = Real.comare
val max = Real.max
val min = Real.min)
structure RBQ5 =
BinomialQueue(type t = real
open Real)
You can see that the instantiation for RBQ5, in addition to not
requiring an ******** name for the structure passed to the functor,
saves some typing by pulling the functions directly from the Real
structure (and, hence, passing a lot of other functions to the
functor, but these are ignored/filtered by the ORDER signature).
Even if the functors you are instantiating don't match the names given
in the Standard Basis, you might find it useful to build a new
structure that can be used to instantiate many of the functors you
find yourself using. For example, it may be a win to define
structure RealArg =
struct
open Real
(* ORDERED *)
type t = real
val eq = ==
val lt = <
...
(* ORD_KEY *)
type ord_key = real (* HASHABLE *)
val hash = fn r => ...
...
end
which gives you one structure to pass to all the functors.
Absolutely. Modules are mostly a means of managing the namespace;
there is only one Real.== function, you've just introduced different
names for the same thing.
|