Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

RFC: Destructuring Assignment (aka Unpacking aka Type Patterns) in pure Perl

by LanX (Saint)
on Jul 02, 2020 at 13:41 UTC ( [id://11118813]=perlmeditation: print w/replies, xml ) Need Help??

At yesterday online meeting of Germany PM we had a discussion about Destructuring Assignment aka unpacking aka Type Patterns which is available in languages like JS (ES6) and Haskell.

I claimed it shouldn't be to difficult to do this in pure Perl, this is what I got so far.

NB: This is a proof of concept !

Neither syntactic sugar nor performance are at it's limits.

(you know "release often ... yadda yadda" ;-)

Grabbing of (almost greedy) lists @arr and %hsh not implemented yet.

Comments welcome.

use strict; use warnings; use Data::Dump qw/pp dd/; use Scalar::Util qw/reftype/; use autovivification; use Test::More; use constant DBG => 0; my @rules; sub parse_arr (\@$) { my ( $arr, $path ) = @_; for ( my $i=0; $i <= @$arr; $i++ ) { my $item = $arr->[$i]; parse( $item, "${path}[$i]"); } } sub parse_hsh (\%$) { my ( $hsh, $path ) = @_; while ( my ($key,$val) = each %$hsh ) { parse( $val, "${path}{$key}"); } } sub parse { my ( $item, $path ) = @_; $path //= ''; my $type = ref $item; return unless $type; if ( $type eq "GRAB") { push @rules, [ $item->{ref} , $path ]; } elsif ( $type eq "ARRAY" ) { parse_arr( @$item, $path ) } elsif ( $type eq "HASH" ) { parse_hsh( %$item, $path ) } else { warn "Unknown $type"; } } sub assign (++){ my ($pattern,$in) =@_; @rules = (); parse($pattern); warn pp @rules if DBG; no autovivification; for my $rule (@rules) { my ($ref,$path) = @$rule; my $code = "\$in->$path"; $$ref = eval($code); } } sub set (\[@$%]) { bless {ref => $_[0]}, "GRAB"; } my @pattern = ( 1,2,3, set my $y , [ 5,6, set my $z ] ); my $src = [ 1,2,3, 42 , [5,6, 666] ]; assign @pattern => $src; is_deeply ( [$z,$y], [666, 42], "AoA grabbing different levels" ); assign { u => [undef, set( my $u )], v => set my $v } => { u => [1,123] , v => "VVV"} ; is_deeply ( [$u,$v], [123,"VVV"], "HoA grabbing different levels" ); done_testing;

C:/Perl_524/bin\perl.exe d:/exp/grab_assign.pl ok 1 - AoA grabbing different levels ok 2 - HoA grabbing different levels 1..2

Cheers Rolf
(addicted to the Perl Programming Language :)
Wikisyntax for the Monastery

Replies are listed 'Best First'.
Re: RFC: Destructuring Assignment (aka Unpacking aka Type Patterns) in pure Perl
by Fletch (Bishop) on Jul 03, 2020 at 20:31 UTC

    I can't easily picture how you'd hammer it into the language without needing parser changes but an Haskell/ML/Erlang destructuring where things are pulled apart based on types and/or guard conditions and the like could be very interesting.

    You might also look at clojure for more inspiration that's a bit closer to the ES6 stuff (I believe).

    E.g. where you can have something like [{:keys [foo bar]} arg_map] which pulls the values at the named keys out of arg_map into vars named after the respective keys.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      > which pulls the values at the named keys out of arg_map into vars named after the respective keys

      That's kind of a hash slice but in a DRY way to avoid typing and typos???

      my ($foo, $bar) = @arg_map{qw/foo bar/} ?

      Sure I can, but I'd need another command and would have a dependency to PadWalker. (Probably)

      Something like set_key(my($foo, $bar)) would just return° the needed pairs from the solution in the OP

      Edit

      °) That is the equivalent to { foo => set my $foo , bar => set my $bar }

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

        Sort of like your slice, but you also can provide default values if things are missing. E.g. if arg_map didn't have anything at the key :foo the variable foo would get be the string "foo missing".

        (let [{:keys [foo bar] :or {foo "foo missing"}} arg_map] ;; ... )

        You'd prossibly need something like my $foo = exists $arg_map{foo} ? $arg_map{foo} : "foo missing" and you'd need to do each variable separately. (I've not messed with clojure in long enough that I'm probably explaining this poorly, to boot . . .)

        The cake is a lie.
        The cake is a lie.
        The cake is a lie.

Re: RFC: Destructuring Assignment (aka Unpacking aka Type Patterns) in pure Perl
by ikegami (Patriarch) on Jul 03, 2020 at 20:03 UTC
      > because it's a workaround for the inability to return multiple value that Perl has naturally.

      O rly? ;)

      const metadata = { title: 'Scratchpad', translations: [ { locale: 'de', localization_tags: [], last_edit: '2014-04-14T08:43:37', url: '/de/docs/Tools/Scratchpad', title: 'JavaScript-Umgebung' } ], url: '/en-US/docs/Tools/Scratchpad' }; let { title: englishTitle, // rename translations: [ { title: localeTitle, // rename }, ], } = metadata; console.log(englishTitle); // "Scratchpad" console.log(localeTitle); // "JavaScript-Umgebung"

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

Re: RFC: Destructuring Assignment (aka Unpacking aka Type Patterns) in pure Perl
by Anonymous Monk on Jul 03, 2020 at 08:38 UTC
    "Assignment"
      Strange, I thought we had a minimal length requirement° for posting ...

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery

      °) alas not one for minimal sense (???)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlmeditation [id://11118813]
Approved by marto
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (5)
As of 2024-04-24 05:53 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found