Search code examples
modulesmlalgebraic-data-types

How to avoid SML datatype repetition in structures and signatures?


Given a signature A with a datatype t, say

signature A = sig
    datatype t = T of int | S of string
end

Is it possible to provide an implementation (a structure) that doesn't have t repeated? For example, in the following signature, the definition of t is repeated. It's fine for small datatypes, but a little clumsy for bigger ones.

structure AImpl : A = struct
    datatype t = T of int | S of string
end

My intention is simply to give an interface, so that one can know all of the declarations. But I don't want every implementation to repeat the datatype definition.

Although it seems that a signature and a structure could both include a datatype from another structure, one would then be unable to know the datatype declaration by inspecting the signature alone. For example:

structure AData = struct
    datatype t = T of int | S of string
end

signature A = sig
    datatype t = datatype AData.t
end

structure a : A = struct
    open AData
end

Of course, this approach, though not that satisfying, is acceptable if I put both AData and A in the same .sig file.


Solution

  • No, it's impossible because of how signature matching rules works in sml.

    When you introduce some non-abstract type in signature every structure with this signature must provide the same type-binding. The reason is that signatures in sml used mainly for hiding structure details.

    For example you can use abstract type to hide datatype details from structure users:

    signature A = 
    sig
      type t
    end
    
    
    structure AImpl :> A = 
    struct
       datatype t = T of int | S of string
    end
    

    Or you can expose just one type constructor:

    signature A = 
    sig
      type t
      val T : int -> t
    end
    
    
    structure AImpl :> A = 
    struct
       datatype t = T of int | S of string
    end
    
    val test = AImpl.T 12;