-
Notifications
You must be signed in to change notification settings - Fork 161
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
Multiple argument lambda functions #490
Conversation
a4b815e
to
8b125cf
Compare
8b125cf
to
0cfee60
Compare
This would be nice to have, IMHO. Just like @ChrisJefferson, the only thing I am mildly concerned about is whether using But my hope is that those two uses would not clash (except perhaps from an aesthetical point of view). |
This shouldn't clash, we can handle it in the same way we already have to handle that Of course, if the saving of '{ }' over 'rec( )' is enough is another question! |
This is not about a replacement syntax for |
Ah, that sounds very reasonable. I'll do the parsing once someone else does the datastructure :) (but let's discuss that somewhere else, at a later date). |
The problem with parsing a hypothetical |
@rbehrends Not sure if this is what you mean, but my understanding (as was explained on issue #37) is that the only issue with Anyway, thinking about that again, I am actually somewhat confused as to why that really is a problem: Basically, after the first comma, we know whether we are looking at e.g. |
Oh wait, now I see, you can actually do this in GAP:
Wow didn't realize this was possible. OK, that kills that idea... (Though, is anybody using that feature? Is the library using this anywhere?) |
@fingolfin wow - never knew that this is possible. |
I've used the following code, to get all permutations which permute two elements, so there is at least one use :) It is hard to search the library, and packages, for uses, as the notation looks too much like a function call.
|
On second thought, it seems to be possible to do this without completely rewriting the parser, borrowing ideas from attribute grammars (attribute grammars can attach semantic information to non-terminals to allow for context-sensitive parsing). While parsing a permutation, you'd track a "maybe a function" flag that remains true as long as the permutation items are identifiers). If that flag becomes false or if the closing parenthesis is not followed by |
While we could do that, there would be issues, as the GAP error reporting assumes we find errors immediately. To see what I mean, consider the following code (notice the placements of the
|
Hm, the sytax
doesn't look very GAP like. Three more ideas:
or, if a double use of
or, if braces are ok, use them around the whole function definition:
Unfortunately, none of these specializes naturally to the case of one argument which we already have. |
Can we somehow get this moving and to a decision? |
We need to agree about the syntax. I will be happy with
considering
or
as well. Unless there will be an obvious agreement, we can used doodle again like we did in #391. |
@frankluebeck I don't understand you remark about this not being "GAP like" - we are talking about a syntax extension here, so of course it's not "GAP like", and I don't find your three alternatives "GAP like" either. Also note that
Personally, I am fine with
|
Just one comment on something @frankluebeck said: Indeed none of our suggestions generalise down to the old single-argument version. However, I think that shows the single-argument version was a mistake -- handling it is a really nasty hack in the parser (although, we will obviously never remove the old single argument version, it has been around for far too long). |
So, perhaps we should make a doodle with some of the options, to get an idea who supports what? Anybody willing to set one up? :) |
Why not - it worked in #391. I've created the poll and added all options in the order in which they have appeared in this thread (if you want to suggest more options, please let me know ASAP):
Please try to make your choice at http://doodle.com/poll/8tty9qg68tz9stc7 within the next several days, to ensure that we make some progress. For each option, you need to specify one of the three possibilities:
It's fine to select "Yes" more than once. Also it's fine to change your mind later and edit your votes. Non-members of the gap-system and gap-packages GitHub organisations may vote too, especially if you have a strong opinion, but please note this is not a binding vote: we only want to have an overview what's the preferred syntax, and hopefully it will be easier for us to make a choice. |
Interesting to think how such notation will look if nested. This hypothetical code takes two arguments and returns a function of another two arguments:
which is good because of matching delimiters. In another notation, it would look like
which looks neat resembling functional programming style, but likely require brackets, what makes it less neat:
|
Is |
@hungaborhorvath |
@alex-konovalov why would it require bracketing? I see no other way of interpreting that expression - perhaps I am overlooking something? |
@fingolfin to help the parser? that was just an assumption, if it could be implemented without brackets - that's even better. Indeed, we don't need brackets to read e.g.
|
The problem with [x,y] is the same as (x,y), we don't know it's the beginning of a function parsing until the end when we find the arrow. That means we need to parse the expression preparing for either case (either introducing new quantifiers, or finding expressions), and finalising at the end. That is possible, but it gets more horrible when we add various natural extensions, like handling 'readonly' arguments in HPC-GAP, or doing |
It seems @ChrisJefferson would you mind updating this PR, rebased on latest master, and adjusted to that syntax, so that we can try it out? |
Updated, try it out and see if there are any issues or tweaks. We can now write zero-argument lambdas in two ways, There are a number of possible extensions we could have on top of this. I'm happy to look into implementing them, but I would ask they get put into new issues unless they would change the user-visible changes in this pull request. |
Current coverage is 49.73% (diff: 92.38%)@@ master #490 diff @@
==========================================
Files 424 424
Lines 223275 223469 +194
Methods 3429 3432 +3
Messages 0 0
Branches 0 0
==========================================
+ Hits 110880 111136 +256
+ Misses 112395 112333 -62
Partials 0 0
|
@ChrisJefferson Thanks for the update! I'll try to review it. Regarding what you wrote: Of course one-argument lambdas in the old syntax must still be supported, there is far too much code relying on it. I am less certain about zero-argument lambdas; those are mostly specific to HPC-GAP, and not much if anything outside of that uses them. So we could still abolish that particular syntax in the future. But of course this PR is not where that would happen. |
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.
This looks pretty solid to me. I only have nitpicky formatting and coverage comments, and an off-topic question.
case S_READWRITE: | ||
if (!is_atomic) { | ||
SyntaxError("'readwrite' argument of non-atomic function"); | ||
GetSymbol(); |
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.
Note that tests do not cover this code block -- I guess we'd have to add another test to tst/testinstall/atomic_basic.tst
where a readwrite
argument occurse in second or later position.
You can of course rightfull argue that this code was not covered before, and you just moved it. Also fine, I just wanted to point it out ;-)
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 added tests for this, and also for lambda (at the moment they are never valid for lambda, as you can't put the initial atomic
. We could invent a notation for that, if we ever want one).
*F ReadFuncArgList( <follow>, <is_atomic>, <is_block>, <symbol>, <symbolstr> ) | ||
** . . . . . . . . . . read a function argument list. | ||
** | ||
** 'ReadFuncArgList' reads the argument list of a function. In case of an error |
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.
This line is too long 8-)
@@ -1469,28 +1526,21 @@ void ReadFuncExpr ( | |||
|
|||
/**************************************************************************** | |||
** | |||
*F ReadFuncExpr1(<follow>) . . . . . . . . . . . read a function expression | |||
*F ReadFuncExprBody(<follow>) . . . . . . . read the body function expression |
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.
This line is too long (remove some of the .
).
@@ -1527,6 +1579,62 @@ void ReadFuncExpr1 ( | |||
|
|||
/**************************************************************************** | |||
** | |||
*F ReadFuncExprLong(<follow>) . . . . . read a multi-arg function expression | |||
** | |||
** 'ReadFuncExprLong' reads an abbreviated function literal expression. 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.
Again a comment line is a bit too long. Just remove some of the double spaces (I think trying to justify format our comments is a silly waste of time anyway).
Of course you may argue that limiting line lengths is silly, too ;-). But then I'd get rid of the /*****...
, too, as it looks weird to have that and then go wider right after it...
TypSymbolSet follow ) | ||
{ | ||
volatile Obj nams; /* list of local variables names */ | ||
volatile Obj name; /* one local variable name */ |
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.
Off-topic question: why are these local variables here and in the other functions volatile
(I know that you just copied it, but perhaps you know)? Is it for HPC-GAP? But why exactly?
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 have no idea. I did just copy it, but I'm positive it can't be doing anything useful.
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.
They are however everywhere, and very old (they come from pre-history, not HPC-GAP), so I'll leave them for now and clean them up later.
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.
Might relate to break loops and the possibility of longjumping in or out of bits of parser. Not sure how,
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 don't see how that would be related either... We could just try it by making a PR which removes all volatile, and see if anything breaks :) See PR #1084
nams = NEW_PLIST( T_PLIST, narg ); | ||
SET_LEN_PLIST( nams, narg ); | ||
TLS(CountNams) += 1; | ||
ASS_LIST( TLS(StackNams), TLS(CountNams), nams ); |
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.
This code is not covered by tests. I assume it is for do/od
blocks with locals? Do we have tests for do/od
blocks already?
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.
In GAP we disabled the parsing for do od
blocks, so I'm fairly sure this can never get called, but obviously haven't removed all the associated code.
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.
Thanks. (I think it would be nice to have do/od blocks in non-HPC GAP, too, but that's clearly beyond the scope of this PR)
Great work. I think the next steps would involve testing this, and documenting it. Ideally, I'd like to see documentation before merging this (as once it's merged, it's there, and we might end up delaying to write documentation for far too long, ending up with a GAP release with this feature undocumented). |
Add support for functions of the form {x,y} -> result. This is actually a very small change, most of the code churn is seperating out function argument parsing so it can be used in both traditional functions and lambda functions.
variable number of arguments this way. | ||
<A>arg-list</A> is a (possibly empty) argument list. Any arguments list | ||
which would be valid for a normal GAP function is also valid here (including | ||
variadic arguments). |
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.
ohh, variadic, nice :)
@@ -1822,23 +1822,55 @@ Also see Chapter <Ref Chap="Functions"/>. | |||
<P/> | |||
<Index Subkey="definition by arrow notation">functions</Index> | |||
<Index>arrow notation for functions</Index> | |||
<C><A>arg-ident</A> -> <A>expr</A></C> | |||
<C>{ <A>arg-list</A> } -> <A>expr</A></C> |
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.
So the old syntax is not documented anymore, is it? But there are still examples for it -- and I think we should still document it. Perhaps like this?
"If the argument list consists of a precisely a single argument, you can also omit the braces."
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.
Carry on a little further (although, it might be a little hidden at the end).
]]></Example> | ||
<P/> | ||
The <C>{</C> and <C>}</C> may be omitted for | ||
functions with one and zero arguments: |
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.
Ahh, here. I overlooked this, sorry.
Hmm, I am still not sure I am happy to document the zero argument variant. I know it's there for HPC-GAP, but I never liked it, and I am not sure we agreed to make it official. I really prefer {}->FOOBAR
over ->FOOBAR
.
I'll not mind terribly if it stays in, though -- but then we should make it clear that this PR also turns this so far inofficial addition into an official one (i.e. let's not "sneak" this 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.
Personally I dislike it, but it's in 4.8, so technically we'd be removing an (undocumented) feature from a stable release. I'm happy to do that, if we decide to do that "officially" too :)
Perhaps it's time to mention this PR on the public gap mailing list, to give a broader audience a last chance to chime in; and then (assuming there is no really good counter argument), merge it in a week or so? @ChrisJefferson Would you consider writing that email? |
In PR gap-system#490 we were wondering why these volatile keywords are there. Let's find out by removing them, and testing the result...
I sent a mail on this to the GAP mailing list on Monday, February 16. I set a reminder for myself, and if there are no protests by coming Wednsday, I'll just merge it. |
Thanks, sorry, I missed you message asking me to write the mail. Too much github traffic recently, I need a better way of making sure I read all the messages I should deal with... |
This is a first attempt at multi-argument lambda functions. The patch looks very big, but most of it is rearranging code, to avoid lots of duplication. The main issue I see with this is the notation. I know previous discussions have been had on this before. My only comment is I tried implementing
(x,y) -> x + y
, and I don't think it's (reasonably) possible, as(x,y)
looks too much like a permutation.The easiest way to demonstrate is with code: