Rob Arthan pointed out that the new behaviour in 5.3 of printing abstract types isn't always desirable and that it might be useful to explain how to restore the old behaviour. I've added an entry to the FAQ http://www.polyml.org/FAQ.html#defaultpretty which includes instructions on how to install a pretty printer that just prints as "?".
David
On Wed, 16 Sep 2009, David Matthews wrote:
Rob Arthan pointed out that the new behaviour in 5.3 of printing abstract types isn't always desirable and that it might be useful to explain how to restore the old behaviour. I've added an entry to the FAQ http://www.polyml.org/FAQ.html#defaultpretty which includes instructions on how to install a pretty printer that just prints as "?".
The paragraph says "This can be included within the abstract type or outside it." According to what you have explained to me earlier, it actually depends if opaque signature matching is involved.
Here is a refined example:
structure Test :> sig type T val x: T exception Err of T val bad: unit -> 'a end = struct
datatype T = T of int;
val x = T 42;
exception Err of T;
fun bad () = raise Err x;
val _ = PolyML.addPrettyPrinter (fn _ => fn _ => fn (_: T) => PolyML.PrettyString "<inner>");
end;
val _ = PolyML.addPrettyPrinter (fn _ => fn _ => fn (_: Test.T) => PolyML.PrettyString "<outer>");
Now the behaviour is like this:
ML> Test.x; val it = <outer> : Test.T ML> Test.bad (); Exception- Err of <inner> raised
Using plain ":" instead of ":>" above will produce "<outer>" in both cases.
Makarius
Makarius wrote:
The paragraph says "This can be included within the abstract type or outside it." According to what you have explained to me earlier, it actually depends if opaque signature matching is involved.
Here is a refined example:
structure Test :> sig type T val x: T exception Err of T val bad: unit -> 'a end = struct
datatype T = T of int;
val x = T 42;
exception Err of T;
fun bad () = raise Err x;
val _ = PolyML.addPrettyPrinter (fn _ => fn _ => fn (_: T) => PolyML.PrettyString "<inner>");
end;
val _ = PolyML.addPrettyPrinter (fn _ => fn _ => fn (_: Test.T) => PolyML.PrettyString "<outer>");
Now the behaviour is like this:
ML> Test.x; val it = <outer> : Test.T ML> Test.bad (); Exception- Err of <inner> raised
Using plain ":" instead of ":>" above will produce "<outer>" in both cases.
I can see your point. To be honest, when I think of an abstract type I think of the abstype construction rather than opaque signature matching. Using abstype here does print "<outer>" in both cases. I should make that more explicit in the FAQ.
There are several things going on here with the opaque matching example. Using an opaque match creates a different type for the purposes of the pretty printer. That's important if the implementing type is something like "int" which already has a pretty printer. In that case it's necessary to install the pretty printer outside the opaque signature otherwise it would over-write the existing pretty printer. If a transparent signature is used types are treated the same for the pretty printer so the outer pretty printer replaces the inner one.
An area that you have brought up which maybe needs to be looked at is the interaction between pretty printers and exceptions. An exception constructor "captures" the pretty print function for the type at its declaration. It doesn't change with the opaque matching. Not only does
Test.bad()
Exception- Err of <inner> raised but also
raise Test.Err Test.x;
The type of (it) contains a free type variable. Setting it to a unique monotype. Exception- Err of <inner> raised
That's certainly not intuitive and even if the former might make a bit of sense the latter is probably confusing.
David
On Wed, 16 Sep 2009, David Matthews wrote:
To be honest, when I think of an abstract type I think of the abstype construction rather than opaque signature matching.
In fact, we are more used to SML90-style signature matching anyway. Some opaque matches were introduced only recently to ensure that certain types loose equality status.
At an intermediate state, I've also tried abstype, but discontinued it again at the point where a structure definition within its body was required. This appears to be illegal, probably because abstype is much older than the structure/signature/functor layer in ML.
Interestingly, opaque signature matching also causes problems in SML/NJ pretty printing. I consider to make another attempt at abstype within a non-opaque structure, trying to avoid the nested structure within the abstract type.
Makarius
On Wed, 16 Sep 2009, Makarius wrote:
On Wed, 16 Sep 2009, David Matthews wrote:
To be honest, when I think of an abstract type I think of the abstype construction rather than opaque signature matching.
Interestingly, opaque signature matching also causes problems in SML/NJ pretty printing. I consider to make another attempt at abstype within a non-opaque structure, trying to avoid the nested structure within the abstract type.
After looking at this again, I've found that all problems disappear if SML97's opaque matching is eliminated. With plain old abstype and SML90's signature matching, pretty printing works again as expected.
Makarius
Makarius wrote:
On Wed, 16 Sep 2009, Makarius wrote:
On Wed, 16 Sep 2009, David Matthews wrote:
To be honest, when I think of an abstract type I think of the abstype construction rather than opaque signature matching.
Interestingly, opaque signature matching also causes problems in SML/NJ pretty printing. I consider to make another attempt at abstype within a non-opaque structure, trying to avoid the nested structure within the abstract type.
After looking at this again, I've found that all problems disappear if SML97's opaque matching is eliminated. With plain old abstype and SML90's signature matching, pretty printing works again as expected.
If you're only installing the pretty printer once it should be all right if you install the pretty printer inside the structure and then apply an opaque signature constraint to the result. The pretty printer will be inherited by the type in the opaque signature. This was what was intended by the section in the FAQ.
If you need to change the pretty printer it's more difficult with an opaque signature. If there's the possibility of an internal pretty printer leaking out through exceptions then you need to install the pretty printer both for the internal type and for the external type.
As you say, these problems don't arise with abstypes and transparent matching. I've updated the FAQ as a result of your comments.
David