NAME
FP::TransparentLazy - lazy evaluation with transparent evaluation
SYNOPSIS
use FP::TransparentLazy;
# This is the same SYNOPSIS as in FP::Lazy but with most `force`
# calls removed, and slightly differing behaviour in places
# (e.g. `$a + 2` will evaluate the thunk here and thus give
# division by zero):
my $a = lazy { 1 / 0 };
eval {
# $a's evaluation is forced here
print $a
};
like $@, qr/^Illegal division by zero/;
eval {
$a + 2
};
like $@, qr/^Illegal division by zero/;
my $count = 0;
my $b = lazy { $count++; 1 / 2 };
is is_promise($b), 1;
is $count, 0;
is $b, 1/2; # increments $count
is $count, 1;
# $b is still a promise at this point (although an evaluated one):
is is_promise($b), 1;
is $b, 1/2; # does not increment $count anymore
is $count, 1;
# The following stores result of `force $b` back into $b
FORCE $b;
is is_promise($b), undef;
is $b, 1/2;
is $count, 1;
# Note that lazy evaluation and mutation usually doesn't mix well -
# lazy programs better be purely functional. Here $tot depends not
# just on the inputs, but also on how many elements were evaluated:
use FP::Stream qw(stream_map); # uses `lazy` internally
use FP::List;
my $tot = 0;
my $l = stream_map sub {
my ($x) = @_;
$tot += $x;
$x*$x
}, list (5,7,8);
is $tot, 0;
is $l->first, 25;
is $tot, 5;
is $l->length, 3;
is $tot, 20;
# Also note that `local` does mutation (even if in a somewhat
# controlled way):
our $foo = "";
sub moo {
my ($bar) = @_;
local $foo = "Hello";
lazy { "$foo $bar" }
}
is moo("you")->force, " you";
is moo("you"), " you";
# runtime conditional lazyness:
sub condprom {
my ($cond) = @_;
lazy_if { 1 / 0 } $cond
}
ok is_promise(condprom 1);
eval {
# immediate division by zero exception (still pays
# the overhead of two subroutine calls, though)
condprom 0
};
like $@, qr/^Illegal division by zero/;
DESCRIPTION
This implements a variant of FP::Lazy that forces promises automatically upon access (and writes their result back to the place they are forced from, like FP::Lazy's `FORCE` does). Otherwise the two are fully interchangeable.
NOTE: this is EXPERIMENTAL. Also, should this be merged with Data::Thunk ?
The drawback of transparency might be more confusion, as it's not directly visible anymore (neither in the debugger nor the source code) what's lazy. Also, transparent forcing will be a bit more expensive CPU wise. Please give feedback about your experiences!
SEE ALSO
NOTE
This is alpha software! Read the status section in the package README or on the website.