develooper Front page | perl.perl5.porters | Postings from June 2021

Re: RFC: Multiple-alias syntax for for

Thread Previous
From:
Ryan Voots
Date:
June 8, 2021 18:14
Subject:
Re: RFC: Multiple-alias syntax for for
Message ID:
CA+sVJXnTWBUpNF2LhQmzSzAVZ8a=eHfG6CWfM_A3cuUvySegRA@mail.gmail.com
For this specific example you can't really make one that does both the hash
iteration and multiple values from a list iteration.  That said you can do
it with keywords currently from a module, see my old example that
implements essentially the entire listed behavior with Keyword::Simple

#!/usr/bin/env perl

use v5.20;

use Keyword::Simple;
use PPR;
use Data::Dumper;
use List::UtilsBy qw/bundle_by/;
use Carp;

BEGIN {
Keyword::Simple::define 'foreach', sub {
    my ($ref) = @_;

    # TODO make this better

    my $scalar_list = qr/
      \((?&PerlVariableScalar)(\s*,\s*(?&PerlVariableScalar))*\)
      |
      (?&PerlVariableScalar)
      $PPR::GRAMMAR
    /x;

    my $regex = qr/\s*
      (?<decl>my\s*)?(?<scalar_list>$scalar_list)
      \s*
      (?<input_value>(?&PerlParenthesesList))
      \s*
      (?<block>(?&PerlBlock))
    /x;

    if ($$ref =~ $regex) {

        my ($input_value, $scalar_list, $block, $decl) = @+{qw/input_value
scalar_list block decl/};
        # do sub here
        my $scalar_count = ($scalar_list =~ y/,//)+1;

        #TODO pick a non-conspicuous name for this
        my $newcode = qq{
            for my \$bundle (bundle_by {[\@_]} $scalar_count, $input_value)
{
                $decl ($scalar_list) = \@\$bundle;

                $block
            }
        };
        my $oldcode = $$ref."";
        substr $$ref, $-[0], $+[0]-$-[0], $newcode; # delete it so i see
all parsing
        #warn "PARSED SUCCESS ".Data::Dumper->Dump( [\%+, $$ref, $oldcode],
[qw/captured changed orig/]);

    } else {
        carp "SYNTAX ERROR";
    }


};
}

package main;

my %hash = (foo => 1, bar => 2);
my @array = (1,2,3, -1,-2,-3);

foreach my ($k, $v) (%hash) {
    say "$k => $v";
}

foreach my ($x, $y, $z) (@array) {
    say "($x, $y, $z)";
}

On Tue, Jun 8, 2021 at 2:09 PM Philip R Brenan <philiprbrenan@gmail.com>
wrote:

> Cicero:  The sinews of Perl are an infinite supply of CPAN.
>
> CPAN contains many variants on this theme as shown in the example below.
> Please tell me how this proposal would improve upon them well enough to
> justify the immense effort of implementing this new feature in the core of
> Perl?
>
> use Test::More qw(no_plan);
> use feature qw(say state current_sub);
>
> sub forEachKeyValue(&%)
>       # Iterate over a hash for each key and value
>  {my ($body, %hash) = @_;
>       # Body to be executed, hash to be iterated
>   &$body($_, $hash{$_}) for sort keys %hash;
>  }
>
> my %h = (a=>1, b=>2, c=>3);
> my @t;
>
> forEachKeyValue
>  {my ($letter, $number) = @_;
>   push @t,  "Letter=$letter, number=$number";
>  } %h;
>
> is_deeply join("\n", @t, ''), <<END;
> Letter=a, number=1
> Letter=b, number=2
> Letter=c, number=3
> END
>
>
> On Tue, Jun 8, 2021 at 6:02 PM Scott Baker <scott@perturb.org> wrote:
>
>> This is a great example.
>>
>> I support this syntax 100%. Well done.
>>
>> On 6/8/2021 4:20 AM, Nicholas Clark wrote:
>> > So, the plan for discussing the proposed RFC process was to feed an idea
>> > through it, and see how we get from idea to RFC to implementation.
>> > (Assuming that we don't reject the idea.)
>> >
>> > About two months ago Rik had mentioned to me the idea of implementing
>> this
>> > (currently illegal) syntax to iterate over hashes:
>> >
>> >      for my ($key, $value) (%hash) { ... }
>> >
>> > which isn't actually hash specific - it generalises to N-at-a-time over
>> any
>> > list.
>> >
>> > I figured that the *runtime* part probably wasn't that hard, so had a
>> crack
>> > implementing that, assuming that I'd get help with the parser part once
>> I
>> > had an idea how the runtime and the optree needed to be. Except that I
>> > didn't get stuck, and got to a complete implementation, which has been
>> > pushed somewhere public for 6 weeks now.
>> >
>> > ( somewhere reachable in 6 clicks from https://github.com/Perl/RFCs )
>> >
>> > So, if you have the time and skills, please try implementing something
>> else
>> > that would improve Perl, as re-implementing this is duplication of
>> effort.
>> >
>> >
>> >
>> > By chance, I started on this a couple of days before KES777 submitted
>> > https://github.com/Perl/perl5/issues/18744
>> > and in turn, that links to a message from Dan Brook in 2017 proposing
>> it:
>> >
>> https://www.nntp.perl.org/group/perl.perl5.porters/2017/03/msg243848.html
>> >
>> >
>> > So, rather than start on the RFC by "faking" an "idea" mail from Rik,
>> I'll
>> > take the genuine item from Dan:
>> >
>> > On Fri, Mar 31, 2017 at 06:39:59PM -0400, Dan Book wrote:
>> >> The "each" function is generally discouraged due to implementation
>> details,
>> >> but is still the most "pretty" and concise way to write such a loop:
>> >>
>> >> while (my ($key, $value) = each %hash) { ... }
>> >>
>> >> A possible alternative to this would be a syntax to alias multiple
>> items
>> >> per iteration in a for/foreach loop.
>> >>
>> >> foreach my ($key, $value) (%hash) { ... }
>> >>
>> >> This could be generalized as a "bundler", in other words to alias a
>> number
>> >> of elements from the list equal to the number of variables specified.
>> Such
>> >> as:
>> >>
>> >> foreach my ($foo, $bar, $baz) (@array) { # $foo, $bar, and $baz are the
>> >> next three elements of @array, or undef if overflowed
>> >>
>> >> I can think of one syntactical issue presently: "foreach ($foo, $bar)"
>> >> without the "my" is already valid syntax so would be difficult to
>> >> disambiguate without looking for the second () denoting the list to
>> iterate
>> >> through.
>> >>
>> >> Thoughts?
>> >>
>> >> -Dan
>> >
>> > This arrives here:
>> >
>> >                                   idea
>> >                                     |
>> >                                     v
>> >                                  mail p5p
>> >                                     |
>> >                    better           |         rejected
>> >                      on     <-------?------->   with
>> >                     CPAN            |         reasoning
>> >                                     v
>> >                                 Draft RFC
>> >                  "we think this idea is worth exploring"
>> >                  (Help us figure out how this will work)
>> >
>> >
>> > For this idea, "we think this idea is worth exploring" applies, so we
>> need
>> > a draft.
>> >
>> >
>> > So
>> >
>> > 1) I need to assign an ID.
>> >
>> > Question - do I start at 0001, or keep low numbers for "something
>> special"?
>> > I'm guessing "start at 0001"
>> >
>> >
>> > 2) Format - PSC had thought Markdown, as many places can render it.
>> >
>> > However,
>> >
>> > a) github itself can render Pod. Is it the only git hosting service
>> that can?
>> > b) I've already found that my local markdown renderer and github
>> disagree
>> >     about nested lists, which is annoying - how many other bugs will I
>> hit?
>> > c) Pod doesn't do tables, but plain markdown doesn't either.
>> >     github extended markdown with tables, but
>> >     i)  How many other markdown implementations follow them?
>> >     ii) Are there alternative competing "table" dialects of Markdown?
>> > d) I'm missing =cut
>> >
>> >
>> > 3) Who is the formal "Author" of this RFC. Does Dan want to be named?
>> >     Currently I seem to be ghost writing it, but if I become the author,
>> >     then someone else needs to take over as sponsor?
>> >     Should the copyright be Dan, and 2017?
>> >
>> >
>> > Appended is my first draft, as if I'd only read Dan's mail.
>> >
>> > I figure that as there has already been some discussion on github in
>> 2021
>> > and p5p in 2017, I should act as if that came in reply to this message,
>> > and try taking this from here, by filling in some of the other sections.
>> >
>> > Nicholas Clark
>> >
>> >
>> >
>> > # Preamble
>> >
>> >      Author:
>> >      Sponsor: Nicholas Clark <nick@ccl4.org>
>> >      ID:      0001
>> >      Status:  Draft
>> >      Title:   Multiple-alias syntax for foreach
>> >
>> > # Abstract
>> >
>> > Implement the currently illegal syntax `for my ($key, $value) (%hash) {
>> ... }` to act as two-at-a-time iteration over hashes. This approach is not
>> specific to hashes - it generalises to n-at-a-time over any list.
>> >
>> > # Motivation
>> >
>> > The `each` function is generally discouraged due to implementation
>> details, but is still the most "pretty" and concise way to write such a
>> loop:
>> >
>> >      while (my ($key, $value) = each %hash) { ... }
>> >
>> > An alternative to this would be a syntax to alias multiple items per
>> iteration in a `for` loop.
>> >
>> >      for my ($key, $value) (%hash) { ... }
>> >
>> > This generalizes as a "bundler" - to alias a number of elements from
>> the list equal to the number of variables specified. Such as:
>> >
>> >      for my ($foo, $bar, $baz) (@array) {
>> >          # $foo, $bar, and $baz are the next three elements of @array,
>> >          # or undef if overflowed
>> >
>> > # Rationale
>> >
>> > The existing syntax to iterate over the keys and values of a hash:
>> >
>> >      while (my ($key, $value) = each %hash) { ... }
>> >
>> > suffers from several problems
>> >
>> > * For correctness it assumes that the internal state of the hash being
>> "clean" - to be robust one should reset the iterator first with `keys
>> %hash;` in void context
>> > * It's hard to teach to beginners - to understand what is going on here
>> one needs to know
>> >    - list assignment
>> >    - empty lists are false; non-empty lists are true
>> >    - that the hash holds an internal iterator
>> > * You can't modify the hash inside the loop without confusing the
>> iterator
>> >
>> > The proposed syntax solves all of these.
>> >
>> > # Specification
>> >
>> > # Backwards Compatibility
>> >
>> > # Security Implications
>> >
>> > # Examples
>> >
>> > *FIXME* - are there useful examples that aren't in the Motivation/
>> >
>> > # Prototype Implementation
>> >
>> > "Here's one I made earlier" applies - we already have one written, so
>> there's no need to duplicate work
>> >
>> > # Rejected Ideas
>> >
>> > # Open Issues
>> >
>> >
>> > # Copyright
>> >
>> > Copyright (C) 2021, Nicholas Clark
>> >
>> > This document and code and documentation within it may be used,
>> redistributed and/or modified under the same terms as Perl itself.
>> >
>>
>

Thread Previous


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About