Skip to content
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

Accessing list entries and record components of expressions #457

Closed
frankluebeck opened this issue Jan 14, 2016 · 12 comments
Closed

Accessing list entries and record components of expressions #457

frankluebeck opened this issue Jan 14, 2016 · 12 comments
Labels
kind: enhancement Label for issues suggesting enhancements; and for pull requests implementing enhancements kind: new feature status: awaiting response Issues and PRs whose progress is stalled awaiting a response from (usually) the author

Comments

@frankluebeck
Copy link
Member

This recalls part of a very old wish list.

Would it be difficult to enhance the GAP parser such that list entries/components can be accessed in any expression that evaluates to a list/record (or positional/component object)?

And similarly for expressions evaluating to functions.

More precisely, it would be great if the follwing code examples would work in the obvlous way:

    gap> "abc"[2];
    Syntax error: ; expected
    "abc"[2];
         ^
    gap> "abc"{[2..3]};
    Syntax error: ; expected
    "abc"{[2..3]};
         ^
    gap> ("abc")[2];
    Syntax error: ; expected
    ("abc")[2];
           ^
    gap> f := function() return [1,2,3]; end;; f()[1];
    1
    gap> (f())[2];
    Syntax error: ; expected
    (f())[2];
         ^
    gap> (f()+1)[2];
    Syntax error: ; expected
    (f()+1)[2];
           ^
    gap> rec(x:=1).x;
    Syntax error: ; expected
    rec(x:=1).x;
             ^
    Error, Variable: 'x' must have a value
    not in any function at line 53 of *stdin*
    gap> (rec(x:=1)).x;
    Syntax error: ; expected
    (rec(x:=1)).x;
               ^
    Error, Variable: 'x' must have a value
    not in any function at line 54 of *stdin*
    gap> (x-> x^2)(3);
    Syntax error: ; expected
    (x-> x^2)(3);
             ^
    gap> f := function() return x->x^2; end;; f()(3);
    9
    gap> (f())(4);
    Syntax error: ; expected
    (f())(4);
         ^
    gap> Group((1,2))!.GeneratorsOfMagmaWithInverses;
    [ (1,2) ]
    gap> (Group((1,2)))!.GeneratorsOfMagmaWithInverses;
    Syntax error: ; expected
    (Group((1,2)))!.GeneratorsOfMagmaWithInverses;
                   ^
    <Attribute "GeneratorsOfMagmaWithInverses">
@fingolfin fingolfin added kind: enhancement Label for issues suggesting enhancements; and for pull requests implementing enhancements kind: new feature labels Jan 14, 2016
@fingolfin
Copy link
Member

+1 :)

@hulpke
Copy link
Contributor

hulpke commented Jan 14, 2016

With me its +2 now. Alexander

On Jan 14, 2016, at 11:12 AM, Max Horn [email protected] wrote:

+1 :)


Reply to this email directly or view it on GitHub.

@ChrisJefferson
Copy link
Contributor

One reason this exists is because of the special casing of assignment (not saying we shouldn't get rid of that, but it's worth considering).

Given f := x -> [x]; then f(1)[1] := 2; works. Should (f(1))[1] := 2 ? What about arbitrary expressions between the brackets?

@stevelinton
Copy link
Contributor

It's not necessarily very difficult, but it's not simple. @ChrisJefferson has put his finger on the main issue -- where is := allowed in this more general world, and what does it mean?

At present, any assignment begins with an identifier, and there is a special section of the parser that parses identifiers followed by arbitrary combinations of [] {} () . without knowing whether it's eventually going to hit a := or not. This would need to be torn up and rethought.

@frankluebeck
Copy link
Member Author

@ChrisJefferson on wrote:

Given f := x -> [x]; then f(1)[1] := 2; works. Should (f(1))[1] := 2 ? What about arbitrary expressions between the brackets?

Yes, this should work. It is difficult to understand why

f := x -> [x]; 
f(1)[1] := 2;
f(1)[(f(1)[1])]:=2;

work, but

f(1)[(f(1))[1]]:=2;

does not.
Of course, all these examples look a bit stupid, but I think one can make up sensible applications for all of them.

@stevelinton wrote:

At present, any assignment begins with an identifier, and there is a special section of the parser that parses identifiers followed by arbitrary combinations of [] {} () . without knowing whether it's eventually going to hit a := or not. This would need to be torn up and rethought.

Ok, I hoped that you can identify the problem, since you have looked at the parser recently.

Maybe these cases can be considered together with two more points on the old wish list (this first was already discussed in #40):

x,y,z := [1,2,3];
R, x := PolynomialRing(Rationals, "x");
Sort(list, (x,y)-> x > y);

@ChrisJefferson
Copy link
Contributor

Another example while I am working through..

M{[1..2]}{[3..4]} := [[1,2],[3,4]]; works because we consider all the {..} together in one go. Handling expressions like (M{[1..2]}){[3..4]} := [[1,2],[3,4]] might be tricky, we could "remember the magic" through the brackets, or treat M{[1..2]} as an expression making a list, and then get assign members {[3..4]} of that list (which would error).

@stevelinton
Copy link
Contributor

Just to pick up one of @frankluebeck's points:
Sort(list, (x,y)-> x > y);

This was discussed as issue #37. The problem is that this syntax cannot always be disentangled from that for a permutation literal without an unfeasible amount of lookahead. In that issue we discussed a numbert of alternative syntaxes (is that the right plural) but reached no conclusion

@ChrisJefferson
Copy link
Contributor

The first request turned out to be easier than I expected. A WIP pull request is at #462 2 (needs more testing, and shouldn't be done by cutting+pasting a chunk of code ). Any comments welcome. Very untested, beyond the examples on this page! Note this patch does not allow assignment to these new expressions.

I think that the second request:

a,b,c := [1,2,3];

Would also not be difficult, however it could rapidly get complicated if people wanted anything deep (splitting multiple levels of list in particular).

Copying the example at the top:

gap> "abc"[2];
'b'
gap> "abc"{[2..3]};
"bc"
gap> ("abc")[2];
'b'
gap> f := function() return [1,2,3]; end;; f()[1];
1
gap> (f())[2];
2
gap> (f()+1)[2];
3
gap> rec(x:=1).x;
1
gap> (rec(x:=1)).x;
1
gap> (x-> x^2)(3);
9
gap> f := function() return x->x^2; end;; f()(3);
9
gap> (f())(4);
16
gap> Group((1,2))!.GeneratorsOfMagmaWithInverses;
[ (1,2) ]
gap> (Group((1,2)))!.GeneratorsOfMagmaWithInverses;

@stevelinton
Copy link
Contributor

On 14 Jan 2016, at 23:59, Christopher Jefferson [email protected] wrote:

The first request turned out to be easier than I expected. A WIP pull request (needs more testing, and shouldn't be done by cutting+pasting a chunk of code). Any comments welcome. Very untested, beyond the examples on this page!

Well done. Am I right in thinking it simply doesn’t support any of the new syntax on the LHS of an assignment? — a good choice if so.

I think that the second request:

a,b,c := [1,2,3];

Would also not be difficult, however it could rapidly get complicated if people wanted anything deep (splitting multiple levels of list in particular).

When this was discussed before people mentioned cases like

y := [4,5,6];
i := 2;
x := y;
x, i, x[i] := [[1,2,3],1,4];

At the end of this, what should x and y be?

The only solution that I can see to be easy for GAP is to evaluate all the LHSs before the RHS so that

y is [4,4,6]
x is [1,2,3]

but I’m not sure that is what people would expect.

Steve


Reply to this email directly or view it on GitHub.

@ChrisJefferson
Copy link
Contributor

Well done. Am I right in thinking it simply doesn’t support any of the new syntax on the LHS of an assignment? — a good choice if so.

Yes. I looked at this a little this morning, and decided it's more horrible than I thought. For example (just to remind people), we parse x[2] := 3 not as y := x[2]; y := 3, but as the single operator \[\]\:\=( list, pos, ix ). Given this (x[2]) := 3, could mean two things:

  1. Keep the 'magic' of ``[]:=`, which requires tracking dereferences through brackets / other operators (sounds really hard, certainly a massive parser change).

  2. Split it into something like y := x[2]; y := 3, which will for many lists cause the assignment to disappear (because as in normal GAP, assigning to y won't assign to x[2]).

With regards the x,y,z := [1,2,3], my temptation is to require the variables are all single identifiers. This is because this needs effectively rearranging into l := [1,2,3]; x := l[1]; y := l[2]; z := l[3];, and if x, y and z are complex expressions (even like x[2]), I'm not sure how we can "store" such partial expressions.

I briefly looked at if we could do (x,y) -> x + y, by parsing a bracketed list and then deciding if it's a perm or a function starter (there is some precedent for that, because when we come to an open bracket it might be the start of a perm or something like (x+y), but it doesn't work, because the things in a function definition (new identifiers) are too different from members of a permutation.

So in short, implementing (x,y) -> x + y is easy, once we have a notation which won't clash with something existing ( @stevelinton mentioned there already exists a list of possibilities )

@fingolfin fingolfin changed the title Accessing list entries and record components Accessing list entries and record components of expressions Jan 15, 2016
@fingolfin
Copy link
Member

For what it's worth:

  1. I see no value in supporting (x) := y or (x[2]) := y or any of that -- this isn't allowed in C either, and people manage. I just learned that it is supported in Python. Oh well, too bad, it's not like we need this.

  2. The discussion on list unpacking / restructuring belong to issue Syntax extension: list unpacking resp. destructuring #40.

  3. We resolve multi argument lambdas a long time ago.

So, in sum, is there anything left to be done about this issue? If so, could somebody who knows please succinctly summarize it? Otherwise, let's close this.

@fingolfin fingolfin added the status: awaiting response Issues and PRs whose progress is stalled awaiting a response from (usually) the author label Dec 20, 2017
@fingolfin
Copy link
Member

No response in the past month from @frankluebeck @ChrisJefferson or anybody else

I am closing this now, feel free to reopen if you think anything in here is left to be done (but it might actually be better to open a new issue then).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
kind: enhancement Label for issues suggesting enhancements; and for pull requests implementing enhancements kind: new feature status: awaiting response Issues and PRs whose progress is stalled awaiting a response from (usually) the author
Projects
None yet
Development

No branches or pull requests

5 participants