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:

  1. perl -slw

    -l sets $\ (the output record separator) to be a newline. This makes the statement

    print join ' ', @_;

    equivalent to

    print join(' ', @_), "\n";
  2. sub nForX(&@)

    This use of subroutine prototypes allows a bare block (not followed by a comma) to replace a subroutine reference as the first argument passed to nForX. Arguments following this subroutine are forced into list context.

  3. &nForX( $code, $n-1, @_, $i );

    The syntax &nForX(...) causes Perl to ignore the prototypes. This is done here to suppress the warning

    main::nForX() called too early to check prototype at ... line ...

    which would otherwise result.

  4. \( @a, @b, @c )

    This “distributes” the reference over each element in the list; so, it’s a convenient shortcut for writing \@a, \@b, \@c.

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,


In reply to Re^3: Massive expansion of a hash of arrays? by Athanasius
in thread Massive expansion of a hash of arrays? by Amblikai

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.