Modules · Language · 1.02
Func::Util
Functional programming utilities, many of them compiled to custom ops.
Memoising, composing, lazy values and safe navigation, with the small checks a program makes all day: is it an array, is it empty, is it between two numbers. Many are custom ops resolved at compile time, so they cost no sub call, and the list searches compare in C with no callback per element.
use Func::Util qw(first_gt dig nvl partition_cb count_cb);
my @orders = map { { id => $_, total => $_ * 40 } } 1 .. 10;
# the first order over 300, compared in C: no callback per element
my $big = first_gt(\@orders, 'total', 300);
print "first over 300: order $big->{id}\n"; # order 8
# safe navigation through nested hashes
my $config = { db => { primary => { host => 'db1' } } };
print dig($config, qw(db primary host)), "\n"; # db1
print nvl(dig($config, qw(db replica host)), 'none'), "\n"; # none
# named predicates, run entirely in C
my ($up, $down) = partition_cb([3, -1, 4, -1, 5], ':is_positive');
print "@$up | @$down\n"; # 3 4 5 | -1 -1
print count_cb([0, 2, 7, 10], ':is_even'), " even\n"; # 3 even
What you get
-
Custom ops
is_array,is_empty,is_between,trim,starts_with,clamp,min2and the rest compile to custom ops, so a check costs a flag test, not a sub call.identityis removed at compile time. -
Searches in C
first_gt,any_eq,all_ltand their kin compare in C, over plain values or a field of each hash, with no Perl callback per element. -
Named predicates
any_cb,grep_cb,count_cbandpartition_cbtake a predicate by name: built-ins such as:is_positiverun entirely in C, andregister_callbackadds your own. -
Functional tools
memo,compose,pipeline,partial,lazyandforce,tapandonce, implemented in XS. -
Data at hand
digwalks nested hashes safely,nvlandcoalescepick the first defined value, andpick,omit,pluck,defaultsanduniqreshape data. -
Said plainly
Its POD says where it does not win: a sub that calls your own code still pays for the call, and calling a
partialmade once is about 20% slower than a closure written by hand.
In use
use Func::Util qw(memo compose pipeline lazy force register_callback any_cb);
# remembered: the second call with the same argument is a lookup
my $calls = 0;
my $square = memo(sub { $calls++; $_[0] * $_[0] });
$square->(12) for 1 .. 3;
print "square(12) = ", $square->(12), " after $calls call\n"; # 144 after 1 call
# functions joined into one
my $slug = compose(sub { lc $_[0] }, sub { join '-', split ' ', $_[0] });
print $slug->('Hello Big World'), "\n"; # hello-big-world
print pipeline(5, sub { $_[0] + 1 }, sub { $_[0] * 10 }), "\n"; # 60
# a value computed once, and only if it is asked for
my $config = lazy(sub { print "loading...\n"; +{ mode => 'live' } });
print force($config)->{mode}, "\n"; # loading... live
print force($config)->{mode}, "\n"; # live
# a predicate of your own, by name
register_callback('over_100', sub { $_[0] > 100 });
print any_cb([5, 50, 500], 'over_100') ? "one is over 100\n" : '';