2008年06月02日 02:30 [Edit]
perl - Scalar::Lazy released!
どんなモジュールかというと、遅延評価をより簡単に扱えるようにします。
use Scalar::Lazy;
my $scalar = lazy { 1 };
print $scalar; # 1;
# Y-combinator made easy
my $zm = sub { my $f = shift;
sub { my $x = shift;
lazy { $f->($x->($x)) }
}->(sub { my $x = shift;
lazy { $f->($x->($x)) }
})};
my $fact = $zm->(sub { my $f = shift;
sub { my $n = shift;
$n < 2 ? 1 : $n * $f->($n - 1) } });
print $fact->(10); # 3628800
遅延評価したい値をlazy{}でくくれば、あら不思議。forceしないでも必要な時に値が出てきます。Y-combinatorの例を見てみて下さい。force相当な部分はどこにもありません。
もしこれをこのモジュールなしで書くとすると、以下のようになります。
my $ZM = sub { my $f = shift;
sub { my $x = shift;
sub { $f->($x->($x)) }
}->(sub { my $x = shift;
sub { $f->($x->($x)) }
})};
my $FORCE = sub { shift };
my $FACT = $ZM->(
sub {
my $f = shift;
sub {
my $n = shift;
$n < 2
? 1
: $n * $f->($FORCE)( $n - 1 );
}
}
)->($FORCE);
forceとそれに対応する括弧が少ない分、かなりわかりやすくなったのではないでしょうか。
Enjoy!
Dan the Perl Monger
See Also:
NAME
Scalar::Lazy - Yet another lazy evaluation in Perl
VERSION
$Id: README,v 0.3 2008/06/01 17:09:08 dankogai Exp dankogai $
SYNOPSIS
use Scalar::Lazy;
my $scalar = lazy { 1 };
print $scalar; # you don't have to force
# Y-combinator made easy
my $zm = sub { my $f = shift;
sub { my $x = shift;
lazy { $f->($x->($x)) }
}->(sub { my $x = shift;
lazy { $f->($x->($x)) }
})};
my $fact = $zm->(sub { my $f = shift;
sub { my $n = shift;
$n < 2 ? 1 : $n * $f->($n - 1) } });
print $fact->(10); # 3628800
DISCUSSION
The classical way to implement lazy evaluation in an eager-evaluating
languages (including perl, of course) is to wrap the value with a
closure:
sub delay{
my $value = shift;
sub { $value }
}
my $l = delay(42);
Then evaluate the closure whenever you need it.
my $v = $l->();
Marking the variable lazy can be easier with prototypes:
sub delay(&){ $_[0] }
my $l = delay { 42 }
But forcing the value is pain in the neck.
This module makes it easier by making the value auto-forcing.
HOW IT WORKS
Check the source. That's what the source is for.
There are various CPAN modules that does what this does. But I found
others too complicated. Hey, the whole code is only 25 lines long!
(Well, was until 0.03) Nicely fits in a good-old terminal screen.
The closest module is Scalar::Defer, a brainchild of Audrey Tang. But I
didn't like the way it (ab)?uses namespace.
Data::Thunk depends too many modules.
And Data::Lazy is overkill.
All I needed was auto-forcing and this module does just that.
EXPORT
"lazy" and "delay".
FUNCTIONS
lazy
lazy { value }
is really:
Scalar::Lazy->new(sub { value });
You can optionally set the second parameter. If set, the value becomes
constant. The folloing example illustrates the difference.
my $x = 0;
my $once = lazy { ++$x } 'init'; # $once is always 1
is $once, 1, 'once';
is $once, 1, 'once';
my $succ = lazy { ++$x }; # $succ always increments $x
isnt $succ, 1, 'succ';
is $succ, 3, 'succ';
delay
an alias to "lazy".
METHODS
new
Makes a lazy variable which auto-forces on demand.
force
You don't really need to call this method (that's the whole point of
this module!) but if you want, you can
my $l = lazy { 1 };
my $v = $l->force;
AUTHOR
Dan Kogai, "<dankogai at dan.co.jp>"
BUGS
Please report any bugs or feature requests to "bug-scalar-lazy at
rt.cpan.org", or through the web interface at
<http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Scalar-Lazy>. I will be
notified, and then you'll automatically be notified of progress on your
bug as I make changes.
SUPPORT
You can find documentation for this module with the perldoc command.
perldoc Scalar::Lazy
You can also look for information at:
* RT: CPAN's request tracker
<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Scalar-Lazy>
* AnnoCPAN: Annotated CPAN documentation
<http://annocpan.org/dist/Scalar-Lazy>
* CPAN Ratings
<http://cpanratings.perl.org/d/Scalar-Lazy>
* Search CPAN
<http://search.cpan.org/dist/Scalar-Lazy>
ACKNOWLEDGEMENTS
Highly inspired by Scalar::Defer by Audrey Tang.
COPYRIGHT & LICENSE
Copyright 2008 Dan Kogai, all rights reserved.
This program is free software; you can redistribute it and/or modify it
under the same terms as Perl itself.
Posted by dankogai at 02:30│Comments(0)│TrackBack(0)