On Fri, 29 Oct 2004 10:29:21 -0600, Siegfried Heintze
<[EMAIL PROTECTED]> wrote:
> I'm trying to understand the map function in perl and have been studying
> David's response to my earlier query.
> 
> When David calls his iterate function, why does he not need to use the
> keyword "sub"? Apparently he is passing a function by reference. Is this a
> block or an expression? The camel book says map takes a block or an
> expression and I don't understand the difference.

A block and an expression are almost interchangeable, the main differences being
a) in the formatting
b) in the use of variable scope.
c) in how a 'result' is determined.

Roughly speaking (ie, without referring to the bible), a block is one or more 
expressions enclosed in curly braces;

1/3    is an expression.  Result is roughly 0.3333333

{ $a=$b; $name="James"; 1+3 } is a block of three expressions, resulting
in the assignment of two variables.  The scope of these particular variables
will be larger than the block, because they are neither defined as
'local' nor 'my'.

The 'Result' of the block is the result of the last expression, or in
this case, 4.

( Please dont confuse ( 1,2,4,5 ) with { 1,2,3,4 } as they are
completely different.
The first is a list of 4 values, while the latter is a block of code
which evaluates to
"4".  )

Perl can take expressions in most places however you need to understand how the
expresion gets interpreted by perl.

Eg,

$a = 1+3

The expression (1+3) is evaluated immediately and the result assigned to $a.

$a = { 4,5,6 }

While '{ 4,5,6 }' as a block results to the number 6, the line above
is illegal perl and
will/should fail to compile. (I'll explain later)

sort { $a cmp $b } @data

Note that here, the 'block' is compiled, and passed to the sort
function.  The expression ($a cmp $b) is not evaluated until the block
needs to be executed,
ie during the sort process.

Just to complicate things,  perl knows when it should expect an expression, or
a block, and whether the block is simply a block (in which it executes each
expression in turn such as a while loop) or whether it is in fact a
named subroutine
('sub jack { block ... }") or anonymous subroutine ( "sort { anonymous
} @data" ) .

Now, referring to code such as :

sub main {
   my $first = 1;

   while ( 1 ) {
       do stuff;
   }

}

'main' is a named subroutine definition, which is essentially a list
of expressions which are put in a bag labelled 'main' and are run in
turn when 'main' is called during
program execution.

The '{ do stuff }' next to the 'while' command is a BLOCK, which is
not treated as a
subrouting definition, and executed immediately during the processing of the
while loop.

As a further example; to take the concept of what perl EXPECTS to find a step
closer to reality consider the following..

$a = { 6+2, 42/6 };

Without any clues to go on, perl will assume that '{ }' are defining a
HASH reference.  This '$a' may contain 'HASH(0xDEADBEEF)'.

Because the { } does not define a block in this case, the contents will be
evaluated immediately, hence $a is equivalent to 
$a->{8} = 7;

$a = sub { 6+2; 42/6 } will result in $a containing 'CODE(0xDEADBEEF)' 
and the contents will include code to determine the result of 6+2 and 42/6.
These expressions will not be evaluated until runtime (for the
purists, I'm purposely
ignoring expression reduction and other optimisations for the sake of
the argument)

Now,  the following command

myfunction { 16/3 } @mydata

is something perl will find perturbing, and should fail once it gets
to the '@' symbol.
This is because the word 'myfunction' should be followed by braces if
it is a function. (so far undeclared)

If you declare the function

sub myfunction;
myfunction { 16/3 } @mydata

you will still get an error because although perl now knows about
'myfunction' it
expects arguments to be 'expressions'.

sub myfunction(&@);
myfunction { 16/3 } @mydata

Here, you have used a prototype to tell perl that 'myfunction' is called with a
block (actually an anonymous function reference) and some data.

Perl then know to expect something tricky when you provide a BLOCK as the
parameter.  This is the only way to "implicitly" provide a BLOCK as a parameter.


Hope that Helps.



> 
> Also, can someone elaborate on his use of prototyping here when he defines
> function iterate? I don't understand the "&@".
> 
> And, what about the use of the keyword "for". Should that not be "foreach"?
> The code works so I guess it is correct.
> 
> Lastly, I tried to rewrite the code so I could understand it. Why does not
> this work?
> 
> sub iterate{
>  my $code = shift;
>  print " begin function iterate\n";
>  foreach $x (@_) { &$code($x) ; }
>  print " end function iterate\n";
> }
> iterate ({ print "Hello $_\n" }, @data);
> 
> Here is what I get:
> cd c:/OpenPerlIDE_1.0.11.409/
> perl test_expression.pl
> Not a CODE reference at test_expression.pl line 5.
> 
> Hello
> 
> begin function iterate
> 
> Compilation exited abnormally with code 255 at Fri Oct 29 10:27:02
> 
> I tried removing the comma from the call to iterate, but that did not help.
> 
>  Thanks,
>     Siegfried
> 
> > On Sun, 10 Oct 2004 14:30:32 -0600, Siegfried Heintze
> <[EMAIL PROTECTED]> wrote:
> > >
> > > The map and the sort statements are strange. Why don't they require a
> > > comma between the first and second arguments?
> >
> > They are not special, they are just using a special semantic built into
> perl.
> >
> > Consider the following:
> >
> ----------------------------------------------------------------------------
> ------------
> > sub iterate(&@)
> > {
> >       my $code = shift;
> >       &$code for @_;
> > }
> >
> > @data = ( "jack", "jill", "jenny" );
> >
> > iterate { print "Hello $_\n" } @data
> >
> ----------------------------------------------------------------------------
> ------------
> >
> > The "iterate" function takes a CODE reference and an ARRAY of stuff (same
> as MAP and GREP and SORT).  It will then blindly iterate over the array of
> stuff and invoke the code for each element.
> >
> > The basic rule is, a BLOCK OF CODE does not require a comma after it,
> because it is self-enclosing (ie, it has braces).
> >
> > Consider then, that since 'map {xx} @data' is actually parsing {xx} as a
> code reference, the same way 'my $prog = { some code}' does, you can also do
> >
> > sub sortfilter($$){
> >     stuff
> > }
> >
> > sort \&sortfilter, @data
> >
> > or even
> >
> > sub special_sort(&@)
> > {
> >      my $sort_func = shift;
> >      sort  $sort_func, @_
> > }
> >
> > You should probably read more on anonymous subroutines and code blocks.
> (and even closures).
> >
> > Cheers.
> > David
> >
> > >
> > > Thanks,
> > >    Siegfried
> 
> --
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
> <http://learn.perl.org/> <http://learn.perl.org/first-response>
> 
>

-- 
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
<http://learn.perl.org/> <http://learn.perl.org/first-response>


Reply via email to