in reply to permutation understanding

Ahh ... recursion!
Ahh ... recursion
Ahh ... recursio
Ahh ... recursi
...

Sounds like you need to focus on recursion right now instead of permutations. Forgive me for dodging the original question, but since the Cookbook really covers this better than i can, i hope my new problem will shed some favorable light. Contemplate this:

use strict; eat('Ahh ... recursion!'); sub eat { my $food = shift; if ($food) { print "$food\n"; eat (substr($food,0,length($food)-1)); } else { # base case return; } }
First, we call the function with a value. Inside this function we check to see if $food is true. Since $food is 'Ahh ... recursion!', it is indeed true, so we print it and call the function again with a new value - the orginal value minus the last character. This continues on and on and on and on until there are no characters left in the variable $food. When we have exhausted $food, the else 'kicks in' and we return - without this, we would be caught in an infinite loop. Well, not really. Because Perl returns (a false value in this example) by default, we don't have to worry about explicitly returning (for this example). You can safely remove the else and it's block, but if you remove the if, the program will loop infinitely.

So, how does this work? Every time you call a subroutine, something has to preserve the arguments you have passed to it. This is implemented internally via a stack. A stack is simply a list that is accessed first-in first-out oops, LAST-in first out (thanks Albannach!), just like a stack of plates at the all-you-can-eat bar. Each call to the function eat() places the argument list on the stack - when the base case (i.e. $food is false) is finally reached, the stack is unwound. Consider this now, the same example using an explicit stack:

use strict; my @stack = ('Ahh ... recursion!'); eat() while @stack; sub eat { my $food = pop @stack; if ($food) { print "$food\n"; push @stack, substr($food,0,length($food)-1); } }
Very similar, but not the same. First, we define the stack with one element: 'Ahh ... recursion!'. Next we call the function eat in a while loop: we eat() until @stack is false (and a false array is one that has no elements).

Inside the function eat(), we first pop the first element out of @stack and store this value in $food. Next we check to see if $food is true (AKA, is not empty). If it is true, we print it, remove the last character, and push back on @stack. This continues until we have removed all the characters - effectively 'eating' the string up. When the string $food is only one character long, we push the result of the final substr (an empty string) onto @stack. Now the while loop fails, and the program ends.

I really hope this helps, because personally, recursion is tough. As a final note, try to understand this program - the Fibonacci sequence (hint - google Fibonacci sequence to learn more):

use strict; my $numb = shift || 20; print fib($numb), "\n"; sub fib { my $n = shift; return 1 if $n < 2; return fib($n - 2) + fib($n - 1); }
UPDATE:
Anony is correct - a better test would have been:
if (length $food) ... # instead of if ($food) ...

jeffa

L-LL-L--L-LL-L--L-LL-L--
-R--R-RR-R--R-RR-R--R-RR
B--B--B--B--B--B--B--B--
H---H---H---H---H---H---
(the triplet paradiddle with high-hat)

Replies are listed 'Best First'.
Re: (jeffa) Re: permutation understanding
by Anonymous Monk on May 25, 2002 at 16:03 UTC
    if ($food) { print "$food\n"; eat (substr($food,0,length($food)-1)); }

    Yes recursion can be instructive, but be careful not to mismatch a conditional test with the logical intent of the test. Your test of true or false doesn't mesh with your logical intent of recursing based on the length of the string. Try eating the string "012345" and your recursion ends too early because a string can have a non-zero length and still be false.

      A simple fix:
      if (exists $food) { }
      Update: Oops, I jumped the gun on that one.

      mr greywolf
        which version of Perl are you using??? exists may be used on hash or array elements or subroutines, not scalar variables.

        Er, what he means is, you want to test for definedness....

        ..Jon

        Update - you're right Anonymous. Mea culpa. My embarrassed apologies to all. )c: