From: David M. <Dav...@pr...> - 2001-10-17 09:39:08
|
I was intrigued by these examples and it set me thinking about whether it was possible to get these to work. After a bit of thought I managed to come up with a solution and try it out in Poly/ML. The critical part of the solution is to realise that unifying an instance of a generic flexible record type involves not only the instance itself but also the generic. For example in, val g = #foo val _ = g {foo = 13, goo = 1.0} g has type {foo:'a, ...} -> 'a after the declaration. Unification of the instance in the second line replaces the 'a by int but in addition it has the effect of adding an extra field (whose type is a new bound variable) to the generic version of g and making it rigid. After the unification g now has type {foo:'a, goo:'b} -> 'a. Poly/ML uses references for type variables (as I guess many implementation do) and creating an instance from a generic type involves copying the type generating new references for each type variable. This normally loses the connection between an instance and the original generic so that unification of an instance does not affect the generic. This solution requires a pointer back from each instance to the corresponding generic. This works on all the examples as well as more complicated ones. I have not, though, decided whether to retain this code in the released version of the compiler. Most other compilers seem to require records to be fully specified at the point where they would be generalised so it might not be helpful to users to have a more generous scheme if they wanted to be able to write portable code. On the other hand, I've come across a number of cases where I've wanted a function to operate on only one or two fields of a labelled record. I've had to add an explicit type constraint or list all the fields just so that the record type is rigid within the function, even though the surrounding context would fully specify it. It's worth noting that this is very similar to the handling of overloading. There again the use of an instance affects the generic. The difference is that because we only have overloading on monotypes there's no need to generalise. If we allowed overloading on polytypes, for instance if + could be overloaded as concatenation of lists, we'd have to use a scheme along these lines. David. On Thursday, October 11, 2001 4:39 PM, Stephen Weeks [SMTP:sw...@in...] wrote: > > Inspired by Andreas' tests, I was trying to understand type inference with > flexible records. I created a few more flexrecord examples (below), and > tried > them out on the SML compilers that I have around. The results are in the > table > below. I would be interested to hear if and an explanation of why the > Definition requires any of these examples to succeed. > > SML/NJ MosML MLton MLKit Poly/ML MLWorks Alice > 110.0.7 2.00 011006 4.0.0 4.1.1 2.0 Oper2 > > flexrecord + + + + + - + > flexrecord2 - + - + - > flexrecord3 - + - + - > flexrecord4 - - - - - > > (* flexrecord2 *) > val _ = > let > val g = #foo > val _ = g {foo = 13} > val _ = g {foo = "yes"} > in > () > end > (* flexrecord2 *) > > (* flexrecord3 *) > val _ = > let > val g = #foo > val _ = g {foo = 13, goo = 1.0} > val _ = g {foo = "yes", goo = 1.0} > in > () > end > (* flexrecord3 *) > > (* flexrecord4 *) > val _ = > let > val g = #foo > val _ = g {foo = 13, goo = 1.0} > val _ = g {foo = "yes", goo = false} > in > () > end > (* flexrecord4 *) > > _______________________________________________ > Sml-implementers mailing list > Sml...@li... > https://lists.sourceforge.net/lists/listinfo/sml-implementers |