czw., 14 mar 2019, 04:22 użytkownik Larry Garfield <la...@garfieldtech.com>
napisał:

> On Wed, Mar 13, 2019, at 6:30 PM, Rowan Collins wrote:
> > On 13/03/2019 21:10, Dik Takken wrote:
> > > So in practice, I expect that
> > > using comprehensions as proposed in the new RFC will also require doing
> > > a lot of iterator_to_array(). A dual comprehension syntax could fix
> that.
> >
> >
> > At risk of complicating things further, might the solution to that be to
> > have a shorter syntax for iterator_to_array in general?
> >
> > It's a shame array-casts are defined for arbitrary objects, else we
> > could have (array)$iterator - and therefore (array)[foreach ($users as
> > $user) yield $user->firstName]
>
> I am again going to reply to a bunch of people at once here...
>
>
> If I can summarize the responses so far, they seem to fall into one of two
> categories:
>
> 1) Love the idea, but wouldn't short-closures be close enough?
>
> 2) Love the idea, but hate the particular syntax proposed.
>
> On the plus side, it seems almost everyone is on board in concept, so
> yay.  That of course just leaves the syntax bikeshedding, which is always
> the fun part.
>
> As an aside, someone up-thread said that comprehensions were "an easier
> way to write foreach loops", which is only true by accident.
> Comprehensions are more formally a way of defining one set in relation to
> another set.  That is, they are a declarative relationship between one set
> and another.  While in PHP that ends up effectively being a short-hand for
> foreach loops, that's more an accidental implementation detail.  The syntax
> used by many other languages to achieve the same thing doesn't look at all
> like loop syntax.
>
> To the question of having both a generator and array version, I would have
> to say no.  As noted in the RFC, most cases where you'd want to use a
> comprehension are not places where you'd be feeding the result into an
> array function.  On the off chance that you are converting the iterable
> into an array is trivial enough that supporting, documenting, and learning
> two slightly different syntaxes seems a net negative.
>
> To Rowan's point, I would be fully in favor of an easier syntax
> alternative to iterator_to_array().  I think that's rather similar
> (although not identical) to the "run out an iterator" add-on mentioned in
> the RFC.  I would support that, but I think it's a bit orthogonal and
> should not be a blocker for short-closures or for comprehensions.
>
> As for the specific syntax, I see a couple of options.
>
> 1) Assuming that short-lambdas get adopted and they can transparently
> support generators, the following syntax becomes automatically possible:
>
> $gen = (fn() => foreach($arr as $k => $v) if ($k % 2) yield $v;)();
>
> While that does work, there's an awful lot of symbol salad there: (fn() =>
> and ;)(); are both just gross and hard to type.  I would consider that not
> a full solution for comprehensions because of how clumsy it is.
>

Have you thought about adopting a keyword which fill look similar as short
closures but by default yield instead of return.
I'm thinking of something like that which looks close to short functions
but shorter:

$arr = [
    'apple' => ['a' => 1],
    'orange' => ['a' => 2],
]
$comprehension = from($arr as $k => ['a' => $a]) => if ($k === 'orange' ||
$a === 1) $a;
$comprehension = from($arr as $k => ['a' => $a]) => {
    if ($k === 'orange') yield $a;
    if ($a === 1) yield $a;
};

The 'from' keyword indicates that it is going to yield from what put in the
parenthesis.

Probably it won't be ambiguous when nesting comprehension.

The example includes also a list array destruct on purpose to show all what
foreach can do.



> 2) We could include an even-shorter-lambda syntax, potentially, or perhaps
> a short-lambda-based comprehension syntax.  For example (and this may not
> be parser friendly but it's just to demonstrate the idea):
>
> $gen = fn{ foreach($arr as $k => $v) if ($k % 2) yield $v };
>
> That would be a short-hand for a short-closure that has no parameters, and
> we could detect the yield and self-execute.  The language inside the
> function body would still be a bit verbose, but it would technically be any
> legal single statement, which would offer some potentially interesting
> (scary?) options.  I would consider this an acceptable solution for
> comprehensions-ish in PHP.
>
> 3) The specific syntax proposed in the RFC is Python-inspired and
> PHP-ified, but there's no reason we need to stick to that.  There are a
> myriad of other syntaxes for comprehensions in other languages that we
> could steal if they fit better, some of which wouldn't at all resemble
> foreach loops and thus avoid the for/foreach confusion.
>
> Wikipedia of course has a large index of them we can mine:
>
>
> https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(list_comprehension)
>
> It appears that the most common syntax involves [] of some variety, which
> pose parsing problems for PHP, but a few other options jump out at me as
> possible syntaxes to pilfer:
>
> C# has this SQL-esque syntax (which may involve too many additional
> language keywords):
>
> var ns = from x in Enumerable.Range(0,100)
>          where x*x > 3
>          select x*2;
>
> Elixr, Erlang, and Haskell use the <- symbol, which... I don't think we
> use anywhere else currently?  In Elixir:
>
> for x <- 0..100, x * x > 3, do: x * 2
>
> Java 8, Ruby, Rust, and Swift are very very similar, and use a fluent
> syntax.  The Rust example:
>
> (0..100).filter(|x| x * x > 3).map(|x| 2 * x).collect();
>
> While that could not be taken as-is, of course, it does propose an
> interesting alternative approach, if we limit comprehensions to Traversable
> objects rather than any iterable (that is, exclude arrays):
>
> $t->filter(fn($v) => expression)->filter(fn($k, $v) =>
> expression)->map(fn($v) => expression);
>
> Which would, in turn, each produce a generator that reduces the set or
> finally yields.  I am not sure I fully like this one, to be honest, as the
> multiple inline short closures make it rather verbose and harder to follow
> with the proposed short-closure syntax (and it would involve more function
> calls internally), but it's an option.  (collect() in these languages seems
> like it's the equivalent of iterator_to_array(); maybe that's another
> alternative there as well?)
>
> Nemerle, which I've never heard of before, has this:
>
> $[x*2 | x in [0 .. 100], x*x > 3]
>
> Which, while $ is obviously already used, does suggest using one of the
> other not-yet-used sigils that Nikita identified, which would let us
> reorder the parameters to put the expression first if we wanted.  For
> example:
>
> ^[$x *2 | $k => $v in $arr if $k %2]
>
>
> In general, I see two alternatives:
>
> 1) Pass short closures and then include a special case of that special
> case that effectively gives us comprehensions over foreach, if, and yield,
> but with fewer seemingly-stray characters.
>
> 2) Steal a completely different syntax from some other language that is
> still terse but less confusing.  The main alternatives to "square brackets
> around a for loop" syntax seem to be:
>
> A) Chained filter() and map() methods
> B) SQL-like keywords
> C) Use <- somehow.
> D) Use a different starting character before the [] so that the parser
> knows some new funky order of stuff is coming.
>
> I am open to both options, of course contingent on someone willing and
> able to code it.
>
> --Larry Garfield
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: http://www.php.net/unsub.php


Great work and I like the idea in general.

BR,
--
Michał Brzuchalski

Reply via email to