SML# Document Version 4.1.0
14 SML# feature: separate compilation

14.6 Functor support

SML# can separately compile functor into an object file, and can be used from other compilation unit through _require declaration. To provide a functor, write the following in its interface file.

functor id(signature) =
struct
  (* the same as Provide declarations of structure *)
end

signature is a Standard ML signature. Below is an example of an interface file for binary search tree.

_require "basis.smi"
functor BalancedBinaryTree
  (A:sig
      type key
      val comp : key * key -> order
    end
  ) =
struct
  type ’a binaryTree (= boxed)
  val empty : ’a binaryTree
  val isEmpty : ’a binaryTree -> bool
  val singleton : key * ’a -> ’a binaryTree
  val insert : ’a binaryTree * A.key * ’a -> ’a binaryTree
  val delete : ’a binaryTree * key -> ’a binaryTree
  val find : ’a binaryTree * A.key -> ’a option
end

In using functors in separate compilation, one should note the following.

  • Functor is not a mechanism for separate compilation. In some existing practice of ML, probably due to the lack of separate compilation, functors can be used to compile some modules independently from the others. For example, if one write

    A.sml file: structure A =
    struct
      ...
    end
    B.sml file: structure B =
    struct
      open A
      ...
    end

    then B.sml file directly depends on A.sml file. If one rewrite B.sml using a functor as below then this dependency can be avoided.

    B.sml file: functor B(A:sig ... end) =
    struct
      open A
      ...
    end

    This is exactly what separate compilation achieves. A system such as SML# where a complete separate compilation is supported, this form of functor usage is unnecessary and undesirable.

  • Usage of functor incurs some overhead. Functors can take types as parameters and therefore strictly more powerful than polymorphic functions. However, this type parameterization requires the compiler to generate code that behaves differently depending on the argument types. The resulting code inevitably incurs more overhead than the corresponding code with the type argument predetermined (i.e. ordinary structures). The programmer who use functor should be aware of this const and restrict functors in cases where the advanced feature of explicit type parameterization is really required.

In the current version of SML# has the following limitation on the usage of functors.

  • If a functor has a formal abstract type constructor with type arguments, only heap-allocated internal representations (such as array, boxed, {}, ->, and *) can be applied to the formal type constructor. The following example causes a compile error in SML#.

    # functor F(type ’a t) = struct end structure X = F(type ’a t = int);
    (interactive):2.17-2.34 Error:
    (name evaluation "440") Functor parameter restriction: t