2

How can I refer to a type in a signature used in a structure that derives the type from the result of a functor. Here is an example using the poly interpreter:

> signature Res = sig type f end;
signature Res = sig type f end
> functor F (A: sig type t end) : Res = struct datatype f = None | Some end;
functor F (A: sig type t end): Res
> structure S = struct local structure A = F(struct type t = int end) in type t = A.f list end end;
structure S: sig type t = A.f list end

First, I don't understand why A.f shows up in the resulting signature when it is local to the structure. Second, how can I create a signature that matches this structure S?

Something like this does not work:

signature SSig = sig type t = F(struct type t = int end).t list end

Also, if the type f is an int instead of a datatype, somehow S ultimately becomes aware that f is an int instead of it being hidden by the signature. This doesn't seem like reasonable behavior even if using opaque signatures doesn't show the int.

> functor F (A: sig type t end) : Res = struct type f = int end;
functor F (A: sig type t end): Res
> structure S = struct local structure A = F(struct type t = int end) in type t = A.f list end end;
structure S: sig type t = int list end
> functor F(A: sig type t end):> Res = struct type f = int end;
functor F (A: sig type t end): Res
> structure S = struct local structure A = F(struct type t = int end) in type t = A.f list end end;
structure S: sig type t = A.f list end
eatonphil
  • 13,115
  • 27
  • 76
  • 133

2 Answers2

2

I don't really have an answer to your first question, just a guess, so I won't comment on that. Andreas Rossberg will probably clarify things there :)

Regarding your second question. I don't understand why you'd want to instantiate a functor inside a signature. Maybe you want this?

signature Res =
  sig
    type f
  end

signature SSig =
  sig
    structure R : Res
    type t = R.f list
  end

And then, whoever implements SSig is free to assign the result of calling F to the R sub-structure.

Regarding your last point. Types are not hidden unless you opaquely implement a signature.

Ionuț G. Stan
  • 176,118
  • 18
  • 189
  • 202
  • I was worried I might have to do this. The issue is that I don't want to make the type t opaque in SSig, but I also don't want to include R in the signature because I don't want consumers to have access to it. I could do a similar thing with an opaque type f = R.f but I'd have to include that in the signature and again that makes the signature messy. To my last point, I was confused because Res does not give the type definition of f. But I guess since F does not use the opaque signature, SML can pull out that to be used in S. – eatonphil Sep 27 '16 at 12:55
1

[...] why A.f shows up in the resulting signature when it is local to the structure.

This appears to be an artifact of Poly/ML. Moscow ML does not seem to leak the name:

Moscow ML version 2.10
Enter `quit();' to quit.
- signature Res = sig type f end;
> signature Res = /\f.{type f = f}
- functor F (A: sig type t end) : Res =
  struct
    datatype f = None | Some
  end;
> functor F : !t.{type t = t}->?=f.{type f = f}
- structure S =
  struct
    local structure A = F(struct type t = int end)
    in type t = A.f list
    end
  end;
> New type names: =f
  structure S : {type t = f list}

How can I refer to a type in a signature used in a structure that derives the type from the result of a functor?

(Comment) The issue is that I don't want to make the type t opaque in SSig, but I also don't want to include R in the signature because I don't want consumers to have access to it. I could do a similar thing with an opaque type f = R.f but I'd have to include that in the signature and again that makes the signature messy.

A recent answer by Drup on how to decide whether to parameterize on the type-level or the module-level when designing modules discusses the drawbacks of monomorphising a module's input types.

Aren't "making t opaque in SSig" and "not including R in the signature of SSig" equivalent when all R contains is type t? Perhaps Res contains more things than type t, in which case you could supply structure R : sig type t end instead. Or perhaps this variation of Ionuț's answer is preferable:

signature Res =
sig
  type t (* rather than structure R *)
  type f = t list
end

functor F (A : sig type t end) : Res =
struct
  type t = A.t
  type f = t list
end

structure S = F(struct type t = int end)

I am unsure of how to avoid the duplication of type f = t list.

Community
  • 1
  • 1
sshine
  • 15,635
  • 1
  • 41
  • 66
  • 1
    Not duplicating `type f` is key. In my real-world code, `type f` is the result of a RedBlackTree functor applied to a String structure. This produces a resulting StringMap structure with a type t. My only option appears to be to create a `type sm` that is set to StringMap.t in the structure or to add a structure of signature REDBLACKTREERES to the signature. But again, I don't want either of these to actually show up in the signature. I'm getting to the point where I'm confused why you refer to the type attached to the structure not the signature. I want to just say REDBLACKTREERES.t. – eatonphil Sep 27 '16 at 15:04
  • 1
    @eatonphil the problem with `REDBLACKTREERES.t` is that functors are generative in SML, which means that types `t` from two different structures created using the same functor won't be treated as equal. That's why types have to come from a structure and not a signature. – Ionuț G. Stan Sep 27 '16 at 16:01
  • @eatonphil why do you want to expose `type f` at all? How is it supposed to be used by clients of that signature? – Ionuț G. Stan Sep 27 '16 at 16:03
  • @eatonphil: Also, thumbs up for referring to "real-world Standard ML code". :-) – sshine Sep 27 '16 at 22:15