This is more of a standard ML question, but I figure folks here will
know. I've always found the situations in which poly/ML allows
polymorphic values (versus forcing a monotype) a bit puzzling. Take
this bit of code, for instance:
datatype 'a box = Empty | Box of 'a
datatype 'a wrap = Wrap of 'a
val box = Box
val wrap = Wrap
val empty = Empty
(* first situation *)
val x = Wrap empty (* polymorphic value : 'a box wrap *)
val y = wrap empty (* monotype : _a box wrap *)
(* second situation *)
fun wrapbox1 x = wrap (box x) (* : 'a -> 'a box wrap *)
val wrapbox2 = wrap o box (* : _a -> _a box wrap *)
In the first situation, its clear that SML treats a type constructor
differently than it's associated function, which makes sense. I've
always treated the "val foo = Foo" syntax as syntactic sugar for "fun
foo x = Foo x". Is this right, or only approximately right?
In the second situation, it seems like the expression "val wrapbox2 =
wrap o box" is forcing "wrap o box" to be executed "too soon", so the
compiler has no choice but to give it a monotype. For instance,
changing the expression to "fn () => (wrap o box)" preserves the
polymorphism.
So, my main question: Is there a reasonable/memorable set of rules for
determining when an expression will produce a polymorphic value as
opposed to a monotype? Is this written down somewhere (e.g. in the SML
97 spec/commentary)?
A second, more specific question: Is there a way for values resulting
from a function call to maintain their polymorphism? That is, can I
produce a polymorphic empty value of type " 'a box wrap " using just
"wrap : 'a -> 'a wrap" and "empty : 'a box"?
Where everything is at the top-level, this doesn't seem necessary.
However, with a bunch of structures and abstract types around, I've
run into this dead end before. Is it possible to get something like
"val empty = Foo.mk (Bar.empty, Baz.empty)", with "Bar.empty : 'a
bar", and "Baz.empty : 'a baz" and "val empty : ('a bar, 'b baz) foo"?
The only solutions I've found are ditching the nice abstract type
Foo.T by moving the datatype def to the signature (boo!) or replacing
"val empty" with "fun empty () = ..." and needing to write "(empty
())" everywhere (double boo!). Does anyone know a nice way around
this?
_______________________________________________
polyml mailing list
[email protected]
http://lists.inf.ed.ac.uk/mailman/listinfo/polyml