Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have in the past written some loops backward (like if) but they were all while or until loops. I have just recently be forced to take a perl class, so to keep myself amused I am trying to get a better grasp of perl's more unique syntax.
I have written $product *= $number for($number;$number >0;$number--);. Yes, this is supposed to be calculating factorial, but it tosses a syntax error at ($number. So I was wondering if for is not compatible with this syntax (google is pulling a scant few useful links, at least none using for in this manner)?

This is my entire program, any way to make the syntax more uniquely perl like would be greatly apprecated as this is how I learn best.
my ($product,@values); @values = (7,38,44,2,0); foreach my $number (@values) { unless($number == 0) { print $number; $product *= $number for($number;$number >0;$number--); print " Factorial is $product\n"; } else { print "0 Factorial is 1\n"; } } exit(0);

Replies are listed 'Best First'.
Re: back iffing with for?
by ysth (Canon) on Apr 06, 2005 at 03:31 UTC

      Don't you mean
      $product *= $_ for 1..$number;
      rather than
      $product *= $number for 1..$number;

      And in this case, you can start at 2:
      $product *= $_ for 2..$number;

Re: back iffing with for?
by crashtest (Curate) on Apr 06, 2005 at 04:21 UTC
    As ysth pointed out, you need to use the non c-style for loop. In addition, you have to initialize $product to 1 each time through the loop. And if you want to make your program more Perl-like, you should always use warnings; (as well as strict) - perl would have complained about the uninitialized $product.

    So, this works for me:
    use strict; use warnings; my ($product,@values); @values = (7,38,44,2,0); foreach my $number (@values) { unless($number == 0) { print $number; # $product *= $number for(1 .. $number); $product = 1; $product *= $_ for(1 .. $number); print " Factorial is $product\n"; } else { print "0 Factorial is 1\n"; } }
Re: back iffing with for?
by tlm (Prior) on Apr 06, 2005 at 10:40 UTC

    Here's how I would recast your snippet:

    use strict; my @values = ( 7, 38, 44, 2, 0 ); for my $number (@values) { my $product = 1; $product *= $_ for 2 .. $number; print "$number Factorial is $product\n"; }
    I moved $product to inside the loop, since it's generally a good idea to limit the scope of variables as much as possible. This precaution is helpful only if running under strict, which I added. (With the exception of the fixing the foreach(;;) syntactic error that ysth already pointed out, the use strict line is probably the most important improvement in the version above.) Also note that the internal for loop does not execute if $number < 2.

    Update: Fixed the missing use strict, and added explanatory remarks.

    the lowliest monk

Re: back iffing with for?
by jhourcle (Prior) on Apr 06, 2005 at 03:39 UTC
      No, that for loops and foreach loops are distinct has no bearing on whether either or both can be used as a statement modifier. for loops cannot. foreach loops can, but only if no index variable is specified.
        Just to (perhaps) clarify, people (including the perl documentation) often use for to mean the c-style loop: for ($he="s"; $a<$jolly; $good+=$fellow) { ... } and foreach to mean the more commonly used iterate-over-a-list loop:
        foreach my $country (qw/I give a fig/) { ... }
        but really "for" and "foreach" are interchangable; both keywords can be used for both types of loops.

        And, people being people, those who know this tend to use the shorter "for" exclusively, which creates a disjunction with how other people refer to the two loop styles. I much prefer to just say C-style for and regular (or no adjective at all) for.

        Perhaps I should have linked to the whole thread, and not merlyn's recent post about the for and foreach distinction.

        Although the keywords may be replaced, the two have distinctly differeny syntax (which the original poster's example shows). The end result is that the two are not completely interchangable.