SlideShare a Scribd company logo
Steven Lembark
Workhorse Computing
lembark@wrkhors.com
There was Spaghetti Code.
And it was bad.
There was Spaghetti Code.
And it was bad.
So we invented Objects.
There was Spaghetti Code.
And it was bad.
So we invented Objects.
Now we have Spaghetti Objects.
Based on Lambda Calculus.
Few basic ideas:
Transparency.
Consistency.
Constant data.
Transparent transforms.
Functions require input.
Output determined fully by inputs.
Avoid internal state & side effects.
time()
random()
readline()
fetchrow_array()
Result: State matters!
Fix: Apply reality.
Used with AWS “Glacier” service.
$0.01/GiB/Month.
Large, cold data (discounts for EiB, PiB).
Uploads require lots of sha256 values.
Uploads chunked in multiples of 1MB.
Digest for each chunk & entire upload.
Result: tree-hash.
Image from Amazon Developer Guide (API Version 2012-06-01)
http://docs.aws.amazon.com/amazonglacier/latest/dev/checksum-calculations.html
sub calc_tree
{
my ($self) = @_;
my $prev_level = 0;
while (scalar @{ $self->{tree}->[$prev_level] } > 1) {
my $curr_level = $prev_level+1;
$self->{tree}->[$curr_level] = [];
my $prev_tree = $self->{tree}->[$prev_level];
my $curr_tree = $self->{tree}->[$curr_level];
my $len = scalar @$prev_tree;
for (my $i = 0; $i < $len; $i += 2) {
if ($len - $i > 1) {
my $a = $prev_tree->[$i];
my $b = $prev_tree->[$i+1];
push @$curr_tree, { hash => sha256( $a->{hash}.$b->{hash} ),
start => $a->{start}, finish => $b->{finish}, joined => 0 };
} else {
push @$curr_tree, $prev_tree->[$i];
}
}
$prev_level = $curr_level;
}
}
Trees are naturally recursive.
Two-step generation:
Split the buffer.
Reduce the hashes.
Reduce pairs.
Until one
value remains.
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 )
}
Reduce pairs.
Until one
value remains.
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 )
}
Tail recursion is common.
“Tail call elimination” recycles stack.
“Fold” is a feature of FP languages.
Reduces the stack to a scalar.
Reset
the stack.
Restart
the sub.
my $foo =
sub
{
@_ > 1 or return $_[0];
@_ = … ;
# new in v5.16
goto __SUB__
};
Voila!
Stack
shrinks.
sub reduce_hash
{
@_ > 1 or return $_[0];
my $count = @_ / 2 + @_ % 2;
@_
= map
{
@_ > 1
? sha256 splice @_, 0, 2
: @_
}
( 1 .. $count );
goto __SUB__
}
Voila!
Stack
shrinks.
@_ =
goto
scare
people.
sub reduce_hash
{
@_ > 1 or return $_[0];
my $count = @_ / 2 + @_ % 2;
@_
= map
{
@_ > 1
? sha256 splice @_, 0, 2
: @_
}
( 1 .. $count );
goto __SUB__
}
See K::D
POD for
{{{…}}}
to avoid
"@_".
use Keyword::Declare;
keyword tree_fold ( Ident $name, Block $new_list )
{
qq # this is source code, not a subref!
{
sub $name
{
@_ > 1 or return $_[0];
@_ = do $new_list;
goto __SUB__
}
}
}
User
supplies
generator
a.k.a
$new_list
tree_fold reduce_hash
{
my $count = @_ / 2 + @_ % 2;
map
{
@_ > 1
? sha256 splice @_, 0, 2
: @_
}
( 1 .. $count )
}
User
supplies
generator.
NQFP:
Hacks the
stack.
tree_fold reduce_hash
{
my $count = @_ / 2 + @_ % 2;
map
{
@_ > 1
? sha256 splice @_, 0, 2
: @_
}
( 1 .. $count )
}
Replace splice
with offsets.
tree_fold reduce_hash
{
my $last = @_ / 2 + @_ % 2 – 1;
map
{
$_[ $_ + 1 ]
? sha256 @_[ $_, $_ + 1 ]
: $_[ $_ ]
}
map
{
2 * $_
}
( 0 .. $last )
}
Replace splice
with offsets.
Still messy:
@_,
stacked map.
tree_fold reduce_hash
{
my $last = @_ / 2 + @_ % 2 – 1;
map
{
$_[ $_ + 1 ]
? sha256 @_[ $_, $_ + 1 ]
: $_[ $_ ]
}
map
{
2 * $_
}
( 0 .. $last )
}
Declare
fold_hash with
parameters.
Caller uses
lexical vars.
keyword tree_fold
(
Ident $name,
List $argz,
Block $stack_op
)
{
...
}
Extract lexical
variables.
See also:
PPI::Token
my @varz # ( '$foo', '$bar' )
= map
{
$_->isa( 'PPI::Token::Symbol' )
? $_->{ content }
: ()
}
map
{
$_->isa( 'PPI::Statement::Expression' )
? @{ $_->{ children } }
: ()
}
@{ $argz->{ children } };
Count & offset
used to extract
stack.
my $lexical = join ',' => @varz;
my $count = @varz;
my $offset = $count -1;
sub $name
{
@_ > 1 or return $_[0];
my $last
= @_ % $count
? int( @_ / $count )
: int( @_ / $count ) - 1
;
...
Interpolate
lexicals,
count, offset,
stack op.
@_
= map
{
my ( $lexical )
= @_[ $_ .. $_ + $offset ];
do $stack_op
}
map
{
$_ * $count
}
( 0 .. $last );
goto __SUB__
Not much
body left:
tree_fold reduce_hash($left, $rite)
{
$rite
? sha2656 $left, $rite
: $left
}
Explicit map,
keyword with
and without
lexicals.
4-32MiB
are good
chunk sizes.
MiB Explicit Implicit Keyword
1 0.02 0.01 0.02
2 0.03 0.03 0.04
4 0.07 0.07 0.07
8 0.14 0.13 0.10
16 0.19 0.18 0.17
32 0.31 0.30 0.26
64 0.50 0.51 0.49
128 1.00 1.02 1.01
256 2.03 2.03 2.03
512 4.05 4.10 4.06
1024 8.10 8.10 8.11
Don’t need Haskell or Scala.
Efficient and elegant functional code.
In Perl 5.
Don’t need Haskell or Scala.
Efficient and elegant functional code.
In Perl 6?
Don’t need Haskell or Scala.
Efficient and elegant functional code.
In Perl 6?
Doubt if even Damian could do it better.
use v6;
sub tree_hash (Str $data, Int :$chunk_size = 1024²) {
reduce_hash
map &sha256,
comb / . ** {1..$chunk_size} /,
$data
}
multi sub reduce_hash ( @nodes) { reduce_hash redigest @nodes }
multi sub reduce_hash ([$node]) { $node }
sub redigest (@list) {
map -> $a, $b? { $b ?? sha256 $a~$b !! $a }, @list;
}
use v6;
sub tree_hash (Str $data, Int :$chunk_size = 1024²) {
reduce_hash
map &sha256,
comb / . ** {1..$chunk_size} /,
$data
}
multi sub reduce_hash ( @nodes) { samewith redigest @nodes }
multi sub reduce_hash ([$node]) { $node }
sub redigest (@list) {
map -> $a, $b? { $b ?? sha256 $a~$b !! $a }, @list;
}
use v6;
sub tree_hash (Str $data, Int :$chunk_size = 1024²) {
reduce_hash
map &sha256,
comb / . ** {1..$chunk_size} /,
$data
}
multi sub reduce_hash (@nodes) {
samewith map -> $a, $b? { $b ?? sha256 $a~$b !! $a }, @nodes
}
multi sub reduce_hash ([$node]) {
$node
}
use v6;
sub tree_hash (Str $data, Int :$chunk_size = 1024²) {
reduce_hash
map &sha256,
comb / . ** {1..$chunk_size} /,
$data
}
sub reduce_hash (@nodes) {
treefold -> $a, $b? { $b ?? sha256 $a~$b !! $a }, @nodes
}
sub treefold (&block, *@data) {
@data > 1 ?? samewith &block, map &block, @data
!! @data[0]
}
use v6;
sub tree_hash (Str $data, Int :$chunk_size = 1024²) {
reduce_hash
map &sha256,
comb / . ** {1..$chunk_size} /,
$data
}
sub reduce_hash (@nodes) {
treefold { sha256 $^a~$^b }, @nodes
}
multi treefold (&block, @data) { |@data }
multi treefold (&block, @data where * >= &block.arity) {
given @data - @data % &block.arity -> $last {
samewith &block, [|map(&block, @data[^$last]), |@data[$last..*]]
}
}
use v6; use Treefold;
sub tree_hash (Str $data, Int :$chunk_size = 1024²) {
reduce_hash
map &sha256,
comb / . ** {1..$chunk_size} /,
$data
}
sub reduce_hash (@nodes) {
treefold { sha256 $^a~$^b }, @nodes
}
use v6; use Treefold;
sub tree_hash (Str $data, Int :$chunk_size = 1024²) {
treefold { sha256 $^a~$^b },
map &sha256,
comb / . ** {1..$chunk_size} /,
$data
}
Don’t need Haskell or Scala.
Efficient and elegant functional code.
In Perl 5 or Perl 6.
Easy to write (once you get the knack).
Easy to optimize (with some syntactic sugar).
Surprisingly efficient.
Give it a try.
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6

More Related Content

PDF
DBIx::Class beginners
PDF
Perl6 Regexen: Reduce the line noise in your code.
PDF
Neatly folding-a-tree
PDF
Metadata-driven Testing
PDF
Findbin libs
PDF
DBIx::Class introduction - 2010
KEY
Good Evils In Perl (Yapc Asia)
DBIx::Class beginners
Perl6 Regexen: Reduce the line noise in your code.
Neatly folding-a-tree
Metadata-driven Testing
Findbin libs
DBIx::Class introduction - 2010
Good Evils In Perl (Yapc Asia)

What's hot (20)

PDF
Perl6 in-production
PDF
Doctrine MongoDB ODM (PDXPHP)
PDF
Perl.Hacks.On.Vim
PDF
Xlab #1: Advantages of functional programming in Java 8
PDF
Adventures in Optimization
PDF
Perl Bag of Tricks - Baltimore Perl mongers
PDF
SPL: The Missing Link in Development
PDF
PHP Language Trivia
PDF
Perl 6 by example
ODP
Introduction to Perl - Day 1
PDF
Simple Ways To Be A Better Programmer (OSCON 2007)
PDF
Parsing JSON with a single regex
PPTX
Creating own language made easy
PDF
Perforce Object and Record Model
PDF
Perl6 grammars
PDF
The Joy of Smartmatch
PDF
Nubilus Perl
PDF
Advanced symfony Techniques
PDF
The Magic Of Tie
Perl6 in-production
Doctrine MongoDB ODM (PDXPHP)
Perl.Hacks.On.Vim
Xlab #1: Advantages of functional programming in Java 8
Adventures in Optimization
Perl Bag of Tricks - Baltimore Perl mongers
SPL: The Missing Link in Development
PHP Language Trivia
Perl 6 by example
Introduction to Perl - Day 1
Simple Ways To Be A Better Programmer (OSCON 2007)
Parsing JSON with a single regex
Creating own language made easy
Perforce Object and Record Model
Perl6 grammars
The Joy of Smartmatch
Nubilus Perl
Advanced symfony Techniques
The Magic Of Tie
Ad

Similar to Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6 (20)

PDF
Short Introduction To "perl -d"
KEY
Achieving Parsing Sanity In Erlang
PPTX
Perl6 a whistle stop tour
PDF
Perl6 a whistle stop tour
PDF
Software Dendrology by Brandon Bloom
PDF
Introduction to Perl
PPTX
Code is not text! How graph technologies can help us to understand our code b...
PDF
From Hand To Mouth (@pavlobaron)
ODP
erlang at hover.in , Devcamp Blr 09
PDF
Scheme on WebAssembly: It is happening!
PDF
Learning Perl 6
PDF
Erlang Message Passing Concurrency, For The Win
PDF
Our Friends the Utils: A highway traveled by wheels we didn't re-invent.
PDF
Hypers and Gathers and Takes! Oh my!
PPTX
unit ii.pptx
PDF
Object::Franger: Wear a Raincoat in your Code
PPTX
D9-Tree and Graph-Data-Structures information.pptx
KEY
Opal compiler
PDF
Memory unmanglement
PDF
perl 6 hands-on tutorial
Short Introduction To "perl -d"
Achieving Parsing Sanity In Erlang
Perl6 a whistle stop tour
Perl6 a whistle stop tour
Software Dendrology by Brandon Bloom
Introduction to Perl
Code is not text! How graph technologies can help us to understand our code b...
From Hand To Mouth (@pavlobaron)
erlang at hover.in , Devcamp Blr 09
Scheme on WebAssembly: It is happening!
Learning Perl 6
Erlang Message Passing Concurrency, For The Win
Our Friends the Utils: A highway traveled by wheels we didn't re-invent.
Hypers and Gathers and Takes! Oh my!
unit ii.pptx
Object::Franger: Wear a Raincoat in your Code
D9-Tree and Graph-Data-Structures information.pptx
Opal compiler
Memory unmanglement
perl 6 hands-on tutorial
Ad

More from Workhorse Computing (20)

PDF
Object::Trampoline: Follow the bouncing object.
PDF
Wheels we didn't re-invent: Perl's Utility Modules
PDF
mro-every.pdf
PDF
Paranormal statistics: Counting What Doesn't Add Up
PDF
The $path to knowledge: What little it take to unit-test Perl.
PDF
Unit Testing Lots of Perl
PDF
Generating & Querying Calendar Tables in Posgresql
PDF
BSDM with BASH: Command Interpolation
PDF
Memory Manglement in Raku
PDF
BASH Variables Part 1: Basic Interpolation
PDF
Effective Benchmarks
PDF
The W-curve and its application.
PDF
Keeping objects healthy with Object::Exercise.
PDF
Smoking docker
PDF
Getting Testy With Perl6
PDF
Light my-fuse
PDF
Paranormal stats
PDF
Shared Object images in Docker: What you need is what you want.
PDF
Putting some "logic" in LVM.
PDF
Selenium sandwich-3: Being where you aren't.
Object::Trampoline: Follow the bouncing object.
Wheels we didn't re-invent: Perl's Utility Modules
mro-every.pdf
Paranormal statistics: Counting What Doesn't Add Up
The $path to knowledge: What little it take to unit-test Perl.
Unit Testing Lots of Perl
Generating & Querying Calendar Tables in Posgresql
BSDM with BASH: Command Interpolation
Memory Manglement in Raku
BASH Variables Part 1: Basic Interpolation
Effective Benchmarks
The W-curve and its application.
Keeping objects healthy with Object::Exercise.
Smoking docker
Getting Testy With Perl6
Light my-fuse
Paranormal stats
Shared Object images in Docker: What you need is what you want.
Putting some "logic" in LVM.
Selenium sandwich-3: Being where you aren't.

Recently uploaded (20)

PPT
“AI and Expert System Decision Support & Business Intelligence Systems”
PDF
Spectral efficient network and resource selection model in 5G networks
PPTX
Cloud computing and distributed systems.
PPT
Teaching material agriculture food technology
PPTX
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
PPTX
Programs and apps: productivity, graphics, security and other tools
PDF
The Rise and Fall of 3GPP – Time for a Sabbatical?
PPTX
Big Data Technologies - Introduction.pptx
PDF
cuic standard and advanced reporting.pdf
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PPTX
Digital-Transformation-Roadmap-for-Companies.pptx
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
PPTX
sap open course for s4hana steps from ECC to s4
PDF
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
PDF
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
PDF
Machine learning based COVID-19 study performance prediction
PPTX
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
“AI and Expert System Decision Support & Business Intelligence Systems”
Spectral efficient network and resource selection model in 5G networks
Cloud computing and distributed systems.
Teaching material agriculture food technology
VMware vSphere Foundation How to Sell Presentation-Ver1.4-2-14-2024.pptx
Programs and apps: productivity, graphics, security and other tools
The Rise and Fall of 3GPP – Time for a Sabbatical?
Big Data Technologies - Introduction.pptx
cuic standard and advanced reporting.pdf
Chapter 3 Spatial Domain Image Processing.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing
Digital-Transformation-Roadmap-for-Companies.pptx
Network Security Unit 5.pdf for BCA BBA.
How UI/UX Design Impacts User Retention in Mobile Apps.pdf
sap open course for s4hana steps from ECC to s4
Profit Center Accounting in SAP S/4HANA, S4F28 Col11
Blue Purple Modern Animated Computer Science Presentation.pdf.pdf
Machine learning based COVID-19 study performance prediction
Effective Security Operations Center (SOC) A Modern, Strategic, and Threat-In...
Advanced methodologies resolving dimensionality complications for autism neur...

Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6

  • 2. There was Spaghetti Code. And it was bad.
  • 3. There was Spaghetti Code. And it was bad. So we invented Objects.
  • 4. There was Spaghetti Code. And it was bad. So we invented Objects. Now we have Spaghetti Objects.
  • 5. Based on Lambda Calculus. Few basic ideas: Transparency. Consistency.
  • 6. Constant data. Transparent transforms. Functions require input. Output determined fully by inputs. Avoid internal state & side effects.
  • 8. Used with AWS “Glacier” service. $0.01/GiB/Month. Large, cold data (discounts for EiB, PiB). Uploads require lots of sha256 values.
  • 9. Uploads chunked in multiples of 1MB. Digest for each chunk & entire upload. Result: tree-hash.
  • 10. Image from Amazon Developer Guide (API Version 2012-06-01) http://docs.aws.amazon.com/amazonglacier/latest/dev/checksum-calculations.html
  • 11. sub calc_tree { my ($self) = @_; my $prev_level = 0; while (scalar @{ $self->{tree}->[$prev_level] } > 1) { my $curr_level = $prev_level+1; $self->{tree}->[$curr_level] = []; my $prev_tree = $self->{tree}->[$prev_level]; my $curr_tree = $self->{tree}->[$curr_level]; my $len = scalar @$prev_tree; for (my $i = 0; $i < $len; $i += 2) { if ($len - $i > 1) { my $a = $prev_tree->[$i]; my $b = $prev_tree->[$i+1]; push @$curr_tree, { hash => sha256( $a->{hash}.$b->{hash} ), start => $a->{start}, finish => $b->{finish}, joined => 0 }; } else { push @$curr_tree, $prev_tree->[$i]; } } $prev_level = $curr_level; } }
  • 12. Trees are naturally recursive. Two-step generation: Split the buffer. Reduce the hashes.
  • 13. Reduce pairs. Until one value remains. 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. Reduce pairs. Until one value remains. 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. Tail recursion is common. “Tail call elimination” recycles stack. “Fold” is a feature of FP languages. Reduces the stack to a scalar.
  • 16. Reset the stack. Restart the sub. my $foo = sub { @_ > 1 or return $_[0]; @_ = … ; # new in v5.16 goto __SUB__ };
  • 17. Voila! Stack shrinks. sub reduce_hash { @_ > 1 or return $_[0]; my $count = @_ / 2 + @_ % 2; @_ = map { @_ > 1 ? sha256 splice @_, 0, 2 : @_ } ( 1 .. $count ); goto __SUB__ }
  • 18. Voila! Stack shrinks. @_ = goto scare people. sub reduce_hash { @_ > 1 or return $_[0]; my $count = @_ / 2 + @_ % 2; @_ = map { @_ > 1 ? sha256 splice @_, 0, 2 : @_ } ( 1 .. $count ); goto __SUB__ }
  • 19. See K::D POD for {{{…}}} to avoid "@_". use Keyword::Declare; keyword tree_fold ( Ident $name, Block $new_list ) { qq # this is source code, not a subref! { sub $name { @_ > 1 or return $_[0]; @_ = do $new_list; goto __SUB__ } } }
  • 20. User supplies generator a.k.a $new_list tree_fold reduce_hash { my $count = @_ / 2 + @_ % 2; map { @_ > 1 ? sha256 splice @_, 0, 2 : @_ } ( 1 .. $count ) }
  • 21. User supplies generator. NQFP: Hacks the stack. tree_fold reduce_hash { my $count = @_ / 2 + @_ % 2; map { @_ > 1 ? sha256 splice @_, 0, 2 : @_ } ( 1 .. $count ) }
  • 22. Replace splice with offsets. tree_fold reduce_hash { my $last = @_ / 2 + @_ % 2 – 1; map { $_[ $_ + 1 ] ? sha256 @_[ $_, $_ + 1 ] : $_[ $_ ] } map { 2 * $_ } ( 0 .. $last ) }
  • 23. Replace splice with offsets. Still messy: @_, stacked map. tree_fold reduce_hash { my $last = @_ / 2 + @_ % 2 – 1; map { $_[ $_ + 1 ] ? sha256 @_[ $_, $_ + 1 ] : $_[ $_ ] } map { 2 * $_ } ( 0 .. $last ) }
  • 24. Declare fold_hash with parameters. Caller uses lexical vars. keyword tree_fold ( Ident $name, List $argz, Block $stack_op ) { ... }
  • 25. Extract lexical variables. See also: PPI::Token my @varz # ( '$foo', '$bar' ) = map { $_->isa( 'PPI::Token::Symbol' ) ? $_->{ content } : () } map { $_->isa( 'PPI::Statement::Expression' ) ? @{ $_->{ children } } : () } @{ $argz->{ children } };
  • 26. Count & offset used to extract stack. my $lexical = join ',' => @varz; my $count = @varz; my $offset = $count -1; sub $name { @_ > 1 or return $_[0]; my $last = @_ % $count ? int( @_ / $count ) : int( @_ / $count ) - 1 ; ...
  • 27. Interpolate lexicals, count, offset, stack op. @_ = map { my ( $lexical ) = @_[ $_ .. $_ + $offset ]; do $stack_op } map { $_ * $count } ( 0 .. $last ); goto __SUB__
  • 28. Not much body left: tree_fold reduce_hash($left, $rite) { $rite ? sha2656 $left, $rite : $left }
  • 29. Explicit map, keyword with and without lexicals. 4-32MiB are good chunk sizes. MiB Explicit Implicit Keyword 1 0.02 0.01 0.02 2 0.03 0.03 0.04 4 0.07 0.07 0.07 8 0.14 0.13 0.10 16 0.19 0.18 0.17 32 0.31 0.30 0.26 64 0.50 0.51 0.49 128 1.00 1.02 1.01 256 2.03 2.03 2.03 512 4.05 4.10 4.06 1024 8.10 8.10 8.11
  • 30. Don’t need Haskell or Scala. Efficient and elegant functional code. In Perl 5.
  • 31. Don’t need Haskell or Scala. Efficient and elegant functional code. In Perl 6?
  • 32. Don’t need Haskell or Scala. Efficient and elegant functional code. In Perl 6? Doubt if even Damian could do it better.
  • 33. use v6; sub tree_hash (Str $data, Int :$chunk_size = 1024²) { reduce_hash map &sha256, comb / . ** {1..$chunk_size} /, $data } multi sub reduce_hash ( @nodes) { reduce_hash redigest @nodes } multi sub reduce_hash ([$node]) { $node } sub redigest (@list) { map -> $a, $b? { $b ?? sha256 $a~$b !! $a }, @list; }
  • 34. use v6; sub tree_hash (Str $data, Int :$chunk_size = 1024²) { reduce_hash map &sha256, comb / . ** {1..$chunk_size} /, $data } multi sub reduce_hash ( @nodes) { samewith redigest @nodes } multi sub reduce_hash ([$node]) { $node } sub redigest (@list) { map -> $a, $b? { $b ?? sha256 $a~$b !! $a }, @list; }
  • 35. use v6; sub tree_hash (Str $data, Int :$chunk_size = 1024²) { reduce_hash map &sha256, comb / . ** {1..$chunk_size} /, $data } multi sub reduce_hash (@nodes) { samewith map -> $a, $b? { $b ?? sha256 $a~$b !! $a }, @nodes } multi sub reduce_hash ([$node]) { $node }
  • 36. use v6; sub tree_hash (Str $data, Int :$chunk_size = 1024²) { reduce_hash map &sha256, comb / . ** {1..$chunk_size} /, $data } sub reduce_hash (@nodes) { treefold -> $a, $b? { $b ?? sha256 $a~$b !! $a }, @nodes } sub treefold (&block, *@data) { @data > 1 ?? samewith &block, map &block, @data !! @data[0] }
  • 37. use v6; sub tree_hash (Str $data, Int :$chunk_size = 1024²) { reduce_hash map &sha256, comb / . ** {1..$chunk_size} /, $data } sub reduce_hash (@nodes) { treefold { sha256 $^a~$^b }, @nodes } multi treefold (&block, @data) { |@data } multi treefold (&block, @data where * >= &block.arity) { given @data - @data % &block.arity -> $last { samewith &block, [|map(&block, @data[^$last]), |@data[$last..*]] } }
  • 38. use v6; use Treefold; sub tree_hash (Str $data, Int :$chunk_size = 1024²) { reduce_hash map &sha256, comb / . ** {1..$chunk_size} /, $data } sub reduce_hash (@nodes) { treefold { sha256 $^a~$^b }, @nodes }
  • 39. use v6; use Treefold; sub tree_hash (Str $data, Int :$chunk_size = 1024²) { treefold { sha256 $^a~$^b }, map &sha256, comb / . ** {1..$chunk_size} /, $data }
  • 40. Don’t need Haskell or Scala. Efficient and elegant functional code. In Perl 5 or Perl 6.
  • 41. Easy to write (once you get the knack). Easy to optimize (with some syntactic sugar). Surprisingly efficient.
  • 42. Give it a try.