Implementing Glacier's Tree Hash using recursive, functional programming in Perl5. With Keyword::Declare we get clean syntax for tail-call elimination. Result is a simple, fast, functional solution.
7. Catch: It doesn't always work.
time()
random()
readline()
fetchrow_array()
Result: State matters!
Fix: Apply reality.
8. Where it does: Tree Hash
Used with AWS “Glacier” service.
$0.01/GiB/Month.
Large, cold data (discounts for EiB, PiB).
Uploads require lots of sha256 values.
13. Pass 1: Reduce the hashes
Reduce pairs.
Until one value
remaining.
sub reduce_hash
{
# undef for empty list
@_ > 1 or return $_[0];
my $count = @_ / 2 + @_ % 2;
reduce_hash
map
{
@_ > 1
? sha256 splice @_, 0, 2
: shift
}
( 1 .. $count )
}
14. Pass 1: Reduce the hashes
Reduce pairs.
Until one value
remaining.
Catch:
Eats Stack
sub reduce_hash
{
# undef for empty list
@_ > 1 or return $_[0];
my $count = @_ / 2 + @_ % 2;
reduce_hash
map
{
@_ > 1
? sha256 splice @_, 0, 2
: shift
}
( 1 .. $count )
}
15. Chasing your tail
Tail recursion is common.
"Tail call elimination" recycles stack.
"Fold" is a feature of FP languages.
Reduces the stack to a scalar.
16. Fold in Perl5
Reset the
stack.
Restart the
sub.
my $foo =
sub
{
@_ > 1 or return $_[0];
@_ = … ;
# new in v5.16
goto __SUB__
};
20. "Fold" is an FP Pattern.
use Keyword::Declare;
keyword tree_fold ( Ident $name, Block $new_list )
{
qq # this is souce code, not a subref!
{
sub $name
{
@_ or return;
( @_ = do $new_list ) > 1;
and goto __SUB__;
$_[0]
}
}
}
See K::D
POD for
{{{…}}}
to avoid
"@_".