Functio...:Utility(3)
πΈ NAME πΈ
Functional::Utility β helper tools for light-weight functional programming.
okay bestie, this is Functional::Utility(3) from the User Contributed Perl Documentation, and it's literally a little toolkit for making certain functional-programming bits easier. slay. π
β¨ SYNOPSIS β¨
Slow down a piece of code, either by delaying $N seconds between runs or by taking $N times as long in between runs as a single run takes:
throttle { print scalar(localtime) . "\n" } delay => $N for 1..5;
throttle { do_something_expensive } factor => $N for 1..5;
Light-weight Moose-style before/after hooks for some arbitrary piece of code:
hook_run(
before => sub { warn "starting up...\n" },
run => $timed_block,
after => sub { warn "...all done!\n" },
);
Allow an anonymous function to be self-recursive without leaking memory:
y_combinator {
my ($recursive_function) = @_;
return sub {
# ... do work ...
$recursive_function->() if some_condition;
return;
};
};
π¦ DESCRIPTION π¦
Functional::Utility provides a small collection of utilities to make certain pieces of functional programming a bit easier. Included are a few tools for controlling the behavior of existing functions.
π EXPORTABLE FUNCTIONS π
πͺ hook_run_hook PRE_CODEREF, CODEREF, POST_CODEREF
πͺ hook_run before => PRE_CODEREF, run => CODEREF, after => POST_CODEREF
Run PRE_CODEREF, then CODEREF, then POST_CODEREF. The return value of hook_run (and hook_run_hook) is the return value of CODEREF. CODEREF will be called in the same context as hook_run itself is called.
To write a light-weight timer function, you might do this:
sub timing_of (&) {
my $block_to_time = shift;
my $start;
return hook_run(
before => sub { $start = time },
run => $block_to_time,
after => sub { warn "code took " . (time - $start) . " seconds to run\n" },
);
}
And then if you had some pieces of code such as this:
my $line = <$fh>;
you could add timing around it by simply saying:
my $line = timing_of { <$fh> };
Since the return value of timing_of() is the return value of hook_run(), you could also write this, if you really cared to read an entire file into memory:
my @lines = <$fh>;
my @lines = timing_of { <$fh> };
Using hook_run(), you might write some more interesting functions beyond stopwatches:
sub nytprof_of (&;$) {
my $profiled_block = shift;
my $profile_output = shift || 'nytprof.out';
require Devel::NYTProf;
return hook_run(
before => sub { Devel::NYTProf->start_profiling },
run => $profiled_block,
after => sub { Devel::NYTProf->stop_profiling },
);
}
π₯ throttle BLOCK delay => N
Run BLOCK, sleeping N seconds between runs.
π₯ throttle BLOCK factor => N
Run BLOCK and time it, and then wait N times as long between runs as the code takes to run.
In order to prevent replication lag between our master/slave database setup, our DBAs request that we limit our inserts to 1,000 at a time and sleep 4 times as long between inserts as the inserts take to run.
I use
throttle { my @binds = @{shift @args}; $sth->execute(@binds) } factor => 4
while @args;
to manage the waiting; @args and $sth are built to accomodate 1,000 entries at a time.
π§ y_combinator BLOCK
My short-sighted view of y_combinator is that it allows you to create a recursive anonymous subroutine in Perl without leaking memory.
Here's a naive recursive anonymous subroutine:
my $factorial;
$factorial = sub {
my $n = shift;
return $n if $n == 1;
return $n * $factorial->($n - 1);
};
my $factorial_6 = $factorial->(6);
If you're committed to using recursive anonymous subroutines in your design, and if you're on a version of perl lower than 5.16 (which introduces the __SUB__ token), then the y_combinator may be just what you need.
my $factorial = y_combinator {
my ($recurse) = @_;
return sub {
my $n = shift;
return $n if $n == 1;
return $n * $recurse->($n - 1);
};
};
my $factorial_6 = $factorial->(6);
For a much stronger treatment of the whats and whys of y_combinator(), view any of the excellent tutorials on this subject; I like http://mvanier.livejournal.com/2897.html
π BUGS AND LIMITATIONS π
The timing_of() function provided in the examples for hook_run() is a bit deceptive, because it ends up timing the overhead of hook_run() in addition to the piece of code being timed. However, if you're timing multiple pieces of code, the overhead of hook_run() will work out to be the same in all cases, at which point the deception is moot.
Currently, two pieces of code may not be throttled at the same time. π
Please report any bugs or feature requests to this project's Github page: <http://github.com/belden/perl-functional-utility/issues>.
π A NOTE ON CONTRIBUTING π
This is a growing collection. You may contribute your own functional utilities via this project's Github page: <http://github.com/belden/perl-functional-utility>.
π COPYRIGHT AND LICENSE π
(c) 2013 by Belden Lyman
This library is free software: you may redistribute it and/or modify it under the same terms as Perl itself; either Perl version 5.8.8 or, at your option, any later version of Perl 5 you may have available.
and that's the whole page, bestie π β this was perl v5.42.2, dated 2023-11-29, from Functio...:Utility(3). periodt. π«Ά
π¦ where this page comes from
- alpine 3.24: perl-functional-utility-doc 1.02-r4 Β· GPL-1.0-or-later OR Artistic-1.0-Perl
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms