Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

functional programming: scan function

by metaperl (Curate)
on Mar 12, 2009 at 19:49 UTC ( #750246=snippet: print w/ replies, xml ) Need Help??

Description: I needed a scan function for some data processing I am doing. Unfortunately Sub::Curried does not work, so I cannot use it's scan function.

Language::Functional has a broken test suite. And I can't figure out how to fix its issues.

fp does not have a scanl function. I considered contributing this code to it, but am turned off by the semantics of the reduce function... I think that would be better named behead. It also potentially conflicts with List::Util in that respect.

So here we have the scanl function, a staple of functional programming, available in standalone fashion. As you can see, it behaves the same as scanl for haskell


use strict; use warnings;
use Data::Dumper;

=for comment

 scanl f q ls = q : case ls of
     []   -> []
     x:xs -> scanl f (f q x) xs

=cut

sub scanl {
    my ($f, $seed, @list)=@_;

    my @tail = @list[ 1 .. $#list ] ;

    my @rest = scalar @list ? scanl($f, $f->($seed, $list[0]), @tail) 
+: ();

    ($seed, @rest);
}


my @lis = (4,2,4);


sub add { $_[0] + $_[1] }
sub divide { $_[0] / $_[1] }

my @result = scanl \&divide, 64, @lis;

warn Dumper(\@result);

 @result = scanl \&divide, 3, ();

warn Dumper(\@result);

use List::Util 'max';

 @result = scanl \&List::Util::max, 5, (1 .. 7) ;

warn Dumper(\@result);

Comment on functional programming: scan function
Download Code
Replies are listed 'Best First'.
Re: functional programming: scan function
by ikegami (Pope) on Mar 12, 2009 at 20:20 UTC
    The expensive recursion can be optimized away. Also, you might also want to specify the "&" prototype to also allow map-like syntax.
    sub scanl(&@) { my ($f, @rv) = @_; $rv[$_] = $f->($rv[$_-1], $rv[$_]) for 1..$#rv; return @rv; } my @rv = scanl \&divide, 64, 4,2,4; -or- my @rv = scanl { $_[0] / $_[1] } 64, 4,2,4;

    Finally, you could use $a and $b instead of $_[0] and $_[1], but that would prevent the use of existing functions directly. If that's not a problem, using $a and $b can be done by assigning references to *$ap and *$bp after doing

    my $pkg = caller(); my $ap = do { no strict 'refs'; \*{$pkg.'::a'} }; local *$ap; my $bp = do { no strict 'refs'; \*{$pkg.'::b'} }; local *$bp;

Back to Snippets Section

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2015-07-28 02:02 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    The top three priorities of my open tasks are (in descending order of likelihood to be worked on) ...









    Results (251 votes), past polls