A functional program
TEST { null ->cons(1)->cons(2)->array } [2,1];
my @b= map { $_*$_ } @a; # hm, map is not taking a function as argument
sub new_counter { my ($n)=@_; sub { $n++ # Ok, that's not actually pure } }
sub odd { my ($n)=@_; $n == 0 ? 0 : even ($n - 1) } sub even { my ($n)=@_; $n == 0 ? 1 : odd ($n - 1) } # oh, Out of memory!
use Method::Signatures; func array_map ($f, $a) { [ map { &$f($_) } @$a ] } func square ($x) { $x * $x } my $b= array_map *square, $a;
sub odd { my ($n)=@_; $n == 0 ? 0 : even ($n - 1) } sub even { my ($n)=@_; $n == 0 ? 1 : odd ($n - 1) } odd 137001 # Out of memory!
to:
use Method::Signatures; use Sub::Call::Tail; func odd ($n) { $n == 0 ? 0 : tail even ($n - 1) } func even ($n) { $n == 0 ? 1 : tail odd ($n - 1) } odd 137001 # -> 1
# alternatively: func odd ($n) { $n == 0 ? 0 : do { @_=($n - 1); goto \&even } } ...
sub odd { my ($n)=@_; $n == 0 ? 0 : even ($n - 1) } sub even { my ($n)=@_; $n == 0 ? 1 : odd ($n - 1) } odd 137001 # Out of memory!
to:
use Method::Signatures; use Sub::Call::Tail; use strict; use warnings; use warnings FATAL => 'uninitialized'; func odd ($n) { $n == 0 ? 0 : tail even ($n - 1) } func even ($n) { $n == 0 ? 1 : tail odd ($n - 1) } odd 137001 # -> 1
sub odd { my ($n)=@_; $n == 0 ? 0 : even ($n - 1) } sub even { my ($n)=@_; $n == 0 ? 1 : odd ($n - 1) } odd 137001 # Out of memory!
to:
use Method::Signatures; use Sub::Call::Tail; use strict; use warnings; use warnings FATAL => 'uninitialized'; # no stringification; func odd ($n) { $n == 0 ? 0 : tail even ($n - 1) } func even ($n) { $n == 0 ? 1 : tail odd ($n - 1) } odd 137001 # -> 1
func outer ($n) { my $inner= func ($n, $tot) { $n > 0 ? &$inner($n-1, $tot*$n) : $tot }; &$inner($n, 1); }
func outer ($n) { my $inner= func ($n, $tot) { $n > 0 ? &$inner($n-1, $tot*$n) : $tot # Global symbol "$inner" }; &$inner($n, 1); }
func outer ($n) { my $inner= func ($n, $tot) { $n > 0 ? &$inner($n-1, $tot*$n) : $tot # Global symbol "$inner" }; &$inner($n, 1); }
change to:
func outer ($n) { my $inner; $inner= func ($n, $tot) { $n > 0 ? &$inner($n-1, $tot*$n) : $tot }; &$inner($n, 1); }
func outer ($n) { my $inner= func ($n, $tot) { $n > 0 ? &$inner($n-1, $tot*$n) : $tot # Global symbol "$inner" }; &$inner($n, 1); }
change to:
func outer ($n) { my $inner; $inner= func ($n, $tot) { # leaks memory! $n > 0 ? &$inner($n-1, $tot*$n) : $tot }; &$inner($n, 1); }
func outer ($n) { my $inner; $inner= func ($n, $tot) { # leaks memory! $n > 0 ? &$inner($n-1, $tot*$n) : $tot }; &$inner($n, 1); } for (1..1e6) { outer 10 };
use Scalar::Util 'weaken'; sub Weakened ($) { my ($ref)= @_; weaken $_[0]; $ref } func outer ($n) { my $inner; $inner= func ($n, $tot) { $n > 0 ? &$inner($n-1, $tot*$n) : $tot }; Weakened($inner)->($n, 1); } for (1..1e6) { outer 10 };
Fixpoint combinator
# in FP::fix func fix ($f) { sub { tail &$f (fix($f), @_) } } func outer ($n) { my $inner= fix func ($inner, $n, $tot) { $n > 0 ? &$inner($n-1, $tot*$n) : $tot }; &$inner($n, 1); }
func compose ($f,$g) { sub { &$f (&$g (@_)) } } func inc ($x) { $x + 1 } func square ($x) { $x * $x } | |
*squareinc= compose *square, *inc; |
# equivalent to func squareinc ($x) { square (inc $x) } |
Functional list generation:
repl> $l= [ 2, undef ] $VAR1 = [ 2, undef ]; repl> $m= [ 1, $l ] $VAR1 = [ 1, [ 2, undef ] ]; repl> $l $VAR1 = [ 2, undef ]; repl> (cons 1, cons 2, null) -> array $VAR1 = [ 1, 2 ];
Haskell:
Prelude> 1 : 2 : [] [1,2]
evaluating expressions only when necessary
repl> $x = lazy { warn "evaluating!"; 2*3 } $VAR1 = bless( ... , 'FP::Lazy::Promise' ); repl> force $x evaluating! at (eval 104) line 1. $VAR1 = 6; repl> force $x $VAR1 = 6; repl> $x = lazy { 1 / 0 } $VAR1 = bless( ... , 'FP::Lazy::Promise' ); repl> force $x Illegal division by zero at (eval 112) line 1.
*Main> let ones = 1 : ones *Main> take 5 ones [1,1,1,1,1] *Main> let alternating = True:False:alternating *Main> take 5 alternating [True,False,True,False,True]
Using functional-perl:
repl> func ones () { my $ones; $ones= lazy { cons 1, $ones }; Weakened $ones } repl> ones->take(5)->array $VAR1 = [ 1,1,1,1,1 ];
Infinite stream calculated on demand:
Prelude> let fibs = 1:1:zipWith (+) fibs (tail fibs) Prelude> take 10 fibs [1,1,2,3,5,8,13,21,34,55]
Using functional-perl:
func fibs () { my $fibs; $fibs= cons 1, cons 1, lazy { stream_zip_with *add, $fibs, rest $fibs }; $fibs } main> fibs->stream_take(10)->array $VAR1 = [ 1,1,2,3,5,8,13,21,34,55 ];
Thanks for listening!
Questions?
Get the code from https://github.com/pflanze/functional-perl
and discuss it on functional-perl.org