-
Notifications
You must be signed in to change notification settings - Fork 236
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
User-defined keywords #3599
base: development
Are you sure you want to change the base?
User-defined keywords #3599
Conversation
3736244
to
62b1eca
Compare
I might stop here, to keep this PR relatively small and to avoid the more controversial items on my list. |
M2/Macaulay2/d/actors5.d
Outdated
w:=makeUniqueWord(s.v, parseinfo(prec,bprec,uprec,parsefuns(u,t))); | ||
when globalLookup(w) is x:Symbol do buildErrorPacket("symbol already in use") | ||
else ( | ||
install(s.v,w); -- TODO check whether install is really needed (for mathematical symbols as opposed to words) |
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.
Are there any updates on whether we need to call install
here?
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.
yeah this is rather subtle. my understanding is, it's harmless to always have install
here (except maybe for a tiny slowdown of the parsing?). The point is, this is useless for keywords that are actual words (like and
) because you need to separate them with spaces anyway (so they behave more similarly to regular symbols). But at the moment I've put limited constraints on allowed keywords (see isvalidkeyword
-- which may require more restrictions), so people can have keywords like @*@
for which install
is definitely necessary.
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 rephrased slightly the comment, but haven't actually changed anything
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 need to think about this some more. Relatedly, at this stage nothing would prevent us from removing the section in lex.d
which you wrote else if ismathoperator(peek2(file)) then (
etc except maybe unicode 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.
answering myself: no that doesn't work. math operators now have a slightly ambiguous status of being both "alphanumeric" (i.e., usable in a regular symbol) and have special parsing rules (so they can be used in keywords, e.g., binary operators).
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.
well, right now, this PR doesn't change the status of math operators, so everything works fine as written.
but yes, as you pointed out, a nice feature of this PR is one can even define unary (prefix) operators which for all practical purposes work the same as a MethodFunction
. so that would definitely be one way forward. might want to have a separate PR for this whole mess. In the meantime, I will fix the install
thing today so we can resolve this particular comment.
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.
it would be so much easier if we could declare math symbols to be non alphanumeric. In fact this was my original idea in my first PR on unicode symbols, but that breaks an existing package which defined the sum and product unicode symbols, so I had to change it. now we're paying the price for this backwards compatibility.
I don't follow this then. How does declaring math symbols to be non-alphanumeric break backwards compatibility with a package that uses non-alphanumeric method names? Unless you meant declare any non-alphanumeric string to be a math operator automatically?
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 agree that we should aim for the ability to declare different types of operators, binary, unary left/right, with prescribed precedents.
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.
it would be so much easier if we could declare math symbols to be non alphanumeric. In fact this was my original idea in my first PR on unicode symbols, but that breaks an existing package which defined the sum and product unicode symbols, so I had to change it. now we're paying the price for this backwards compatibility.
I don't follow this then. How does declaring math symbols to be non-alphanumeric break backwards compatibility with a package that uses non-alphanumeric method names?
you mean, with a package that uses math-operator method names?
because methods have ordinary symbols (as opposed to keywords), and these are required to be alphanumeric.
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.
updated so install
is only called when needed.
Since lots of things are being refactored here, what do you think about also changing the terminology? My understanding is that the classes So I think we should create a new class |
sure. |
though it would be nice to have a common ancestor, since I don't want to have two different methods |
I guess what I'm saying is we should not have edit: to clarify, a |
⋯:=symbol ⋯ | ||
⋱:=symbol ⋱ | ||
⋮:=symbol ⋮ | ||
…:=symbol … | ||
-- used e.g. in chaincomplexes.m2 |
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'm confused about what's happening here, and also don't think this particular syntax is good practice.
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.
For instance, maybe cdots = ⋯ = new Operator from symbol ⋯
is preferable, and later in this file it would be better to use the synonym cdots
rather than ⋯
.
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.
well, what was there before was worse, since it defined a sub-Type of Symbol
, which is not a good idea in general. this has the merit that it works.
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.
but OK with synonyms, done
protect Flexible | ||
protect Binary | ||
protect Prefix | ||
protect Postfix |
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.
How come Flexible is kept here?
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.
Tangentially, I think a syntax like:
otimes = ⊗ = new BinaryOperator from symbol ⊗
otimes.precedence = precedence symbol *
would be nice, though perhaps for flexible operators it's a bit more tricky.
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.
the problem with using the syntax new ... from symbol ...
is that there is no room for options, and I'm not sure how to implement this .precedence
thing.
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.
How come Flexible is kept here?
dunno I didn't touch 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.
should I have moved Flexible
too? I'm not even clear what it means.
more generally I don't know what operatorAttributes
is for, so I didn't touch it.
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.
dunno I didn't touch this
You removed protect Binary
and Prefix
and Postfix
but kept Flexible
here. Why?
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.
well, besides what I wrote above, the practical reason was that I didn't need Flexible
.
err? that's exactly what this PR is doing... Example
|
to recap: two types of
both are (and should be) definable using |
oh yeah this PR also fixes this silly bug: |
If a user can define |
sure, I'm happy to name it something else. but the point is, for all practical purposes, in that example, |
Then users should not be able to define them in the top level. They should be defined in the interpreter, compiled, and fixed in the language. |
well, I disagree. It certainly doesn't harm to give users that power. |
It certainly does harm if it's hastily implemented without much longer discussion and evaluation. What happens if a package makes Again, I'm all in favor of allowing users to define non-alphanumeric math operators in the top level, because those can't be used as symbols for methods or variables, and we already know how to deal with different packages overriding the same method, but keywords are by definition preserved words which can't be altered by the user. |
actually, it makes no difference whether the keyword is alphanumeric or not. there will be a conflict if two packages define the same keyword. Right now it's a non issue because no package does so, but eventually we need a mechanism to resolve if say two different packages want to use |
To clarify, |
Let me try to summarise some of the changes that have been requested during the M2internals meeting:
|
Limiting Perhaps a good place to start is a wiki or discussion page where you lay out a proposal (similar to Python Enhancement Proposals) with concise technical specifications of how you believe keywords/operators/etc should be handled, from parsing and binding in the interpreter all the way to the packages. This can simultaneously serve as a documentation of your contribution to this part of the interpreter. This can be discussed and amended, until there's agreement. |
Work in progress to implement user-defined keywords: (cf #3593)
The most important change is to have a default operation (which applies to 99% of existing keywords, and to the newly created user-defined keywords) which is to look up the corresponding method. so no need to define all these identical functions one-by-one.
TODO:
treat all the different cases (unary, binary, precedence) by adding options to the m2 levelmakeKeyword
simplify drasticallyactors5.d
by removing all unnecessary functionsopsWithBinaryMethod
etcgetBinopName
etc and rewritepseudocode
accordinglysimplify thetex
routinesKeyword
class, instead providing some information in theSymbol
Afterprint
fix the other minor issues mentioned in User-created keywords #3593documentmakeKeyword