Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Re^2: Massive expansion of a hash of arrays?

by Amblikai (Scribe)
on Jul 17, 2014 at 22:45 UTC ( [id://1094135]=note: print w/replies, xml ) Need Help??


in reply to Re: Massive expansion of a hash of arrays?
in thread Massive expansion of a hash of arrays?

Ok, i've come across this example of recursion from another user on this forum BrowserUk But i'm having trouble understanding it. Could anyone help?

Re^3: Variable number of foreach loops

The code is below:

#! perl -slw use strict; sub nForX(&@) { my $code = shift; my $n = shift; return $code->( @_ ) unless $n; for my $i ( @{ shift() } ) { &nForX( $code, $n-1, @_, $i ); } } my @a = 1..10; my @b = 'a'..'z'; my @c = map chr, 33 .. 47; nForX { print join ' ', @_; } 3, \( @a, @b, @c );

Anyone? Thanks.

Replies are listed 'Best First'.
Re^3: Massive expansion of a hash of arrays?
by Athanasius (Archbishop) on Jul 19, 2014 at 08:09 UTC

    OK, I’ll have a go at explaining how this works. But note first that BrowserUk produced his elegant solution by exploiting some of the less-well-known features of Perl syntax. Let’s get them out of the way first:

    Now to the recursion. (1) On the first call, $code is initialised to the block { print join ' ', @_; }, and $n is set to 3. As 3 is non-zero, the call to return $code->(@_) is skipped. The for loop which follows is equivalent to this:

    for my $i (1, 2, 3, 4, 5, 6, 7, 8, 9, 10) { &nForX($code, 2, \@b, \@c, $i); }

    The first iteration of this loop calls nForX for the second time, as follows:

    &nForX($code, 2, \@b, \@c, 1);

    (2) Within this second call, $code is set as before, and $n is 2. The for loop is now equivalent to this:

    for my $i ('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', + 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' +) { &nForX($code, 1, \@c, 1, $i); }

    On its first iteration, it calls nForX for the third time, as follows:

    &nForX($code, 1, \@c, 1, 'a');

    (3) Within this third call, $n is 1, and the loop is now this:

    for my $i ('!', '"', '#', '$', '%', '&', "'", '(', ')', '*', '+', ',', + '-', '.', '/') { &nForX($code, 0, 1, 'a', $i); }

    On its first iteration, this loop calls nForX for the fourth time, as follows:

    &nForX($code, 0, 1, 'a', '!');

    (4) Within this fourth call, $n is now zero, so the sub ends with the statement return $code->(@_);, which is here equivalent to:

    return print join ' ', 1, 'a', '!';

    So at this point, the first line of output is printed, and a “true” value is returned to the caller, which was the third call to nForX. That third call throws the return value away, and proceeds to the next iteration of its for loop, which is equivalent to this:

    &nForX($code, 0, 1, 'a', '"');

    — and so on and so on, until all the calls to nForX have returned and all the loops are exhausted. (As am I, after all that!)

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Thank you so much for taking the time to explain this code. There was a lot in there that i couldn't get my head around, so your explanation is very much appreciated. I'm actually now using the code so it's good that i now know how it works!!

      A final point, i tried to move the subroutine definition below the code calling it (I like to keep all my subs at the bottom), but i get an error:

      Can't call method "nForX" without a package or object reference at ./test.pl line 617.

      Is there a reason for this? And how do i store the sub somewhere else?

        A final point, i tried to move the subroutine definition below the code calling it (I like to keep all my subs at the bottom), but i get an error: Can't call method "nForX" without a package or object reference at ./test.pl line 617.
        It seems you'll need to add a forward declaration with the prototype in order to move the sub definition below the calling code.

        sub nForX(&@); ... nForX { print join ' ', @_; } 3, \( @a, @b, @c ); ... sub nForX(&@) { #use of prototype here is actually irrelevant #now, i.e. sub nForX {...} works the same ... }

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (5)
As of 2024-04-19 11:20 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found