FunctionalPerl
view release on metacpan or search on metacpan
docs/blog/perl-weekly-challenges-113.md view on Meta::CPAN
Left (check chosen')
It should now be straight-forward to see the equivalence of the
implementations.
Interestingly, the Haskell version, compiled with `-O2`, is only about
twice as fast as the Perl implementation. But to be fair, my Perl
version is using an array to hold `$ns`, wheras I use the linked list
in Haskell, and a hash table in Perl, whereas `Data.Set` is a tree in
Haskell. Also, since the algorithm finds most solutions with only very
few iterations, what we're mostly benchmarking is the setting up of
the initial data: the creation of `1..$N`, conversion to strings,
filtering according to `$D`, conversion to the hashmap/Set. This is
very optimized in the Perl core, and probably somewhat less so
(compared to other things) in Haskell. I'm also using `Integer` in the
Haskell version which is safe against wraparounds, but more costly;
replacing it with `Int` makes it about 1.5x faster, and is just about
as safe as Perl's ints are (propagation to floating point numbers
would break things, too, if it weren't academic on a 64-bit machine).
Like mentioned in the previous section, the code could probably be written
docs/design.md view on Meta::CPAN
# The design principles used in the functional-perl library
<with_toc>
## General
### Be properly functional first.
As already mentioned in the introduction on the [[howto]] page, the
modules are built using the functional paradigm from the ground up (as
much as makes sense; e.g. iterations in simple functions are often
written as loops instead of tail
recursion<small><sup>1</sup></small>). A sequences API to build
alternative implementations (like iterator based, or optimizing away
intermediate results) might be added in the future.
<small><sup>1</sup> But this is mainly done just because it's
(currently) faster, and since currently Perl does not offer
first-class continuations. Avoiding loop syntax and using function
calls everwhere makes it possible to suspend and resume execution
arbitrarily in a language like Scheme, without mutation getting in the
docs/intro.md view on Meta::CPAN
This uses a new instance of `$i` in each iteration, as you can see
from this:
fperl> $VAR1->map(fun ($v) { &$v() })
$VAR1 = list(1, 2, 3);
There's one potential problem with this, though, which is that perl
allocates a new frame on the call stack for every nested call to
`build`, which means it needs memory proportional to the number of
iterations. But perl also offers a solution for this:
fperl> sub build ($i,$l) { if ($i > 0) { @_ = ($i-1, cons fun () { $i }, $l); goto &build } else { $l }}
Sorry for the one-line formatting here, our examples are starting to
get a bit long for the repl, here is the same with line breaks:
sub build ($i,$l) {
if ($i > 0) {
@_ = ($i-1, cons fun () { $i }, $l);
goto &build
intro/more_tailcalls view on Meta::CPAN
#
# @_ = ($x - 1, $x * $res);
# goto \&functional_fact_iter
#
# or, with nicer looks, by using Sub::Call::Tail:
tail functional_fact_iter($x - 1, $x * $res)
}
}
# To really see the difference, here's a function that we can usefully
# test for higher numbers of iterations:
func odd($n) {
if ($n == 0) {
0
} else {
even($n - 1)
}
}
func even($n) {
intro/tailcalls view on Meta::CPAN
@_ = ($x - 1, $x * $res);
goto \&functional_fact_iter
# Yes that's rather ugly; see the file `more_tailcalls`
# for a better-looking way.
}
}
# To really see the difference, here's a function that we can usefully
# test for higher numbers of iterations:
sub odd {
my ($n) = @_;
if ($n == 0) {
0
} else {
even($n - 1)
}
}
lib/Chj/time_this.pm view on Meta::CPAN
my $res = time_this { somefunc(66) } "somefunc"; # included in message
# or
my $res = time_this { somefunc(66) }
msg => "somefunc", n => 10; # run thunk 10 times
# or
my $res = time_this { somefunc(66) } out => \@t; # push to @t instead of stderr
=head1 DESCRIPTION
Currently does not divide the timings by the number of iterations.
Currently does not subtract the overhead of calling the thunk (as
Benchmark.pm does, but can't use it since it doesn't return values;
should we wrap and use assignment instead? But then timings are off
again.)
Also should probably follow the output format of Benchmark.pm
=head1 SEE ALSO
( run in 0.926 second using v1.01-cache-2.11-cpan-71847e10f99 )