Ch.11 Separate compilation in SML#

§ 11.5. Treatment of signatures

In Standard ML, in addition to resources explained in Section 11.3, signatures are also named resources. For example,one should be able to provide QUEUE signature as well as Queue structure. In require declaration in an interface file, signature files can be specified in the following syntax.

_require sigFilePath

sigFilePath is a path to a signature file. To understand this mechanism, let us review some properties of Standard ML signatures.

  • A signature may reference some types define in some other structures.

  • A signature itself does not define any type.

To deal with this situation properly, SML# compiler treats _require sigFilePath declaration as follows.

  • Evaluate the signature in the file sigFilePath in the context generated by all the other Require declarations.

  • The signature declaration is inserted at the beginning of the source file that use this interface file through _require.

Figure 11.3 shows an interface file containing an opaque signature.

queue-sig.sml file:

signature Queue =
sig
  datatype 'a queue = Q of 'a list * 'a list
  exception Dequeue
  val empty : 'a queue
  val isEmpty : 'a queue -> bool
  val enqueue : 'a queue * 'a -> 'a queue
  val dequeue : 'a queue -> 'a queue * 'a
end

queue.smi file:

_require "basis.smi"
_require "queue-sig.sml"
 
structure Queue =
struct
  type 'a queue (= boxed)
  exception Dequeue
  val empty : 'a queue
  val isEmpty : 'a queue -> bool
  val enqueue : 'a queue * 'a -> 'a queue
  val dequeue : 'a queue -> 'a queue * 'a
end

queue.sml file:

structure Queue : QUEUE =
struct
  datatype 'a queue = Q of 'a list * 'a list
  exception Dequeue
  val empty = Q ([],[])
  fun isEmpty (Q ([],[])) = true
    | isEmpty _ = false
  fun enqueue (Q(Old,New),x) = Q (Old,x::New)}
  fun dequeue (Q (hd::tl,New)) = (Q (tl,New), hd)
    | dequeue (Q ([],_) = raise Dequeue
    | dequeue (Q(Old,New) = dequeue (Q(rev New,[]))
end
Figure 11.3. Example of interface file with signatures