-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove polymorphic variants using module namespacing #487
Conversation
Pattern.t is now Pattern.with_pos, Pattern.node is now Pattern.t
This will allow to avoid name clashes after converting phrasenode datatype to an ordinary variant datatype (instead of current polymorphic variant implementation)
I think this is a good argument to settle the debate on type-directed disambiguation by just accepting that we use it and disable the corresponding warning.
This sounds like a reasonable thing to do and much better than creating mutually recursive modules.
I would rather have some clutter than trying to be clever about the ordering of patterns. Once we allow type-directed disambiguation, the local |
We can't disable the warnings because they are right. Like I said, with type-directed disambiguation the compiler picks one of the datatypes in scope, and it usually picks the wrong one. I pushed the refactoring further and redefined almost all sugartypes as ordinary variants. Few minor definitions remain and I am working on them. I'd say that the amount of extra clutter is reasonable and acceptable. |
Also, put all the datatype-related datatype definitions into a module
This looks like progress to me. How close does it get us to being able to reconsider using |
Note to self and @rudihorn:
But |
@rudihorn, I got stuck on refactoring unary operators in Sugartypes due to the way the code interacts with lenses stuff. The problem is with |
Also, create a CommonTypes module to store simple definitions used throughout the compiler.
@rudihorn, you can ignore the above question now. I've found a good way to break the module cycle. |
This PR is ready for review. Things of interest:
If there are no objections I'd like to merge on Monday. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To stay in today's metaphor: You're doing god's work, Janek!
core/sugarTraversals.ml
Outdated
| `Table (_x, _x_i1, _x_i2) -> | ||
let _x_i1 = o#datatype _x_i1 in Mu (_x, _x_i1) | ||
| Forall (_x, _x_i1) -> | ||
let _x = _x in |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason for keeping this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Absolutely no. Good catch. Fixed.
core/commonTypes.ml
Outdated
end | ||
|
||
(* Convenient aliases for constructing values *) | ||
let resAny = Restriction.Any |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're essentially introducing aliases for the more generically named variants like Any
, by introducing linAny
, resAny
. In my opinion, this just shows that those constructors should be renamed. Effectively, only the aliases you define here are used in the rest of the code, so we could just rename the underlying constructors. What do the others think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only the aliases you define here are used in the rest of the code
To be more precise: only aliases are used for constructing values. For deconstructing them (pattern matching) we still use constructors, for these types usually with explicit qualification. As for renaming the constructors to ResAny
, LinAny
, etc. - because I understand that's what you're proposing - I wonder what others think. Sam criticized this as poor man's namespaces, so I went with modules. Perhaps a middle ground here is shortening the names of modules to Lin
, DecLin
, Res
, PrKind
? We could then remove the aliases because spelling out the module name wouldn't be that painful.
Rant: I wish OCaml had pattern synonyms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I quite like the prefix, it is informative. But I wouldn't be opposed to the good ol' single letter prefix on constructor names either.
I am slightly concerned about rebasing the proper-modules branch on top of this. Although, I suppose I'll just leave that task to @frank-emrich... |
@dhil: thanks for feedback, all fixed now. |
A while back I started an email thread about warnings generated by the compiler when several datatypes share the same constructor. In such cases compiler uses type-directed disambiguation and for the most time it guesses wrong. Ideas to solve the problem included:
I wasn't happy with (1) because it meant awkward clutter. Sam pointed out that (3) is a poor-man's namespacing. So I decided to experiment with (2) to see how it works out. I placed
pattern
andpatternode
datatypes in aPattern
module like this:and then changed all the code accordingly. Thoughts, questions and observations:
let open Pattern in
, unless we only match on one or two constructors, in which case I used name quantification. Even withlet open
quantification is sometimes required because OCaml is not very good at type inference:Here if
Any
isn't prefixed the compiler complains about type-directed disambiguation. An alternative solution is to putNil
branch first, becauseNil
does not appear in other datatypes (yet):This generally works, but it might force us to order branches in an unintuitive order. Another annoying part was the parser, where every use of constructor has to be prefixed.
Is all that clutter acceptable? Perhaps a shorter module name (
Pat
?) would be better?Pattern.t
is now a pattern with position, whilePattern.node
is just a pattern. Is that intuitive? Now that I wrote this I am having thoughts that a more intuitive naming would be to havePattern.t
as the pattern datatype with all the constructors andPattern.with_pos
as pattern with position.In Sugartypes there is a long series of definitions of mutually recursive datatypes that include
phrase
,binding
, and all the accompanying datatype definitions. Within that group two constructors incp_phrasenode
(Select
,Offer
) are repeated in other datatypes. I am leaning strongly towards prefixing all constructors incp_phrasenode
withCP
. This would mean that the whole recursive group can remain as is, without the need of putting all the datatype definitions into mutually recursive modules.Unrelated to this PR, I think some datatypes would perhaps be better kept as polymorphic variants. I am in particular thinking about
freedom
. The reason is its interaction withTypes.Vars.flavour
and subtype casting fromfreedom
toflavour
(e.g. infree_bound_type_vars
). While a direct cast can be easily replaced with a function (a small runtime expense), we also seem to be using subtyping on data structures. From my understanding of code this would require rebuilding the whole data structure just to perform a cast on elemnents stored inside, which is potentially a large runtime expense.Any thoughts and feedback welcome.