Would you (or someone else) be willing to explain the Haskell code to me or P5ers who don't know Haskell?

```=== haskell ===

--data type Tree is
--either
--    a Leaf containing a single item (of type a)
-- or
--   a Node containing two subtrees (that can have leaves of type a)
data Tree a = Leaf a | Node (Tree a) (Tree a)
-- and it inherits 'methods' / 'roles' from types Show and Eq,
deriving (Show, Eq)

-- Fringe is a function that extracts a list of type a from a tree con
+taining type a
fringe :: Tree a -> [a]

-- If its argument is of type leaf
-- it returns a single element list containing the element held in the
+ leaf
fringe (Leaf x) = [x]

-- If its argument is a Node
-- it returns the list returned by the left subtree
-- concatenated to the list returned by the right subtree
fringe (Node n1 n2) = fringe n1 ++ fringe n2

-- sameFringe takes two Trees as its arguments
-- and uses the == method inherited/included from the Eq role
-- to compare the lists returned from the two trees for equality
-- returning true if they are the same.
sameFringe :: (Eq a) => Tree a -> Tree a -> Bool
sameFringe t1 t2 = fringe t1 == fringe t2

Personally, I find the Perl6 far easier to read. I'd be very happy to use Perl6 if it had threading and ran at perl5 speed.

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
• Comment on Re: Haskell vs Perl 6 (was Re: Capturing parenthesis and grouping square brackets)

Replies are listed 'Best First'.
Re^2: Haskell vs Perl 6 (was Re: Capturing parenthesis and grouping square brackets)
by Jenda (Abbot) on Jul 03, 2013 at 13:48 UTC

I'd add a note saying something like "While the code looks like the two trees are flattened to lists first and then compared, Haskell is lazy, which means that behind the scenes it will only do as much work as it has to and stop flattening once it finds the first mismatch. Simply don't worry about it. It works."

I've read both codes and both explanations (the fact that the one for Haskell is quite a bit shorter is telling. On a Perl forum.) and still think the Haskell code is much clearer and cleaner.

A better explanation of the Perl6 code might help somewhat. "take yields a value that is added to a gather'd list." Humpf?!? "Cool is a flavor of undef." Whatafuck?

Heck the all fringe(\$a) Z=== fringe(\$b) alone is crazy enough to require two pages of explanation.

Jenda
Enoch was right!
Enjoy the last years of Rome.

A better explanation of the Perl6 code might help somewhat.

If you look at Re: Challenge: Perl 5: lazy sameFringe()? (threads::Gather Configurably truely lazy or semi-lazy), you see a Perl5 implementation that more closely mirrors the Haskell variant.

It uses a home brewed implementation of take & gather that uses a thread and a queue under the covers to provide a truly lazy process.

That homebrew take/gather looks like this:

```#! perl -slw
use strict;
use Exporter;

our @ISA = qw[ Exporter threads::Q ];
our @EXPORT = qw[ take gather ];

sub take;

sub gather (&\$@) {
no strict 'refs';# no warnings 'redefine';
my( \$code, \$Qsize ) = ( shift, shift );
my \$Q = threads::Q->new( \$Qsize );
my \$caller = caller;
local *{ "\$caller\:\:take" } = sub (_) { \$Q->nq( @_ ); };
local \$^R = \$code;
async( sub{ &\$code; \$Q->nq( undef ); }, @_ )->detach;
return sub { \$Q->dq; };
}

return 1 if caller;

The take() sub is only available within the gather code block, and simple pushes its argument(s) onto a queue.

The code block itself is run in a separate thread; and the return of the gather sub is an iterator that simply dequeues values from the queue.

If teh size of the queue is set to 1, then each it take() will block the queue until the value it pushed is popped off using the iterator.

Not efficient -- a thread swap for every leaf -- but truly lazy.

If you supply a bigger queue size than one -- on the call to gather(), then gather block will be able to take() that many values before blocking and a thread swap is forces; thus you get a 'batching' behaviour which is more efficient.

This is (I suspect) the intent of the perl6 take/gather "at some future point in time", but currently it take is simply a push to a hidden array and once all the values have been collected, the gather subroutine iterates over that array popping them off as it goes. (See Perl6::Gather for a crude Perl5 implementation.)

But, as of yet -- and if I am any judge, for the foreseeable future -- that "at some future point in time" is unlikely to ever arrive.

Not that threading is the only way a lazy take/gather could be implemented. It could be done today in Perl5 using Coro if that runs where you live.

It could also be done using green (user space) threading; or continuations; or go-style goroutines. And if you believe the P6 specs, it intends to support all of those and more.

But, when (to my knowledge) there has been no (ZERO) attempt to provide and flavour of multitasking in any of the p6-ish interpreters, it doesn't look likely. YOU cannot add this stuff successfully as an after thought; you have to architect it in from the ground up or you end up with iThreads or similar.

And it is actually quite easy to do, if you do it from the start. As soon as the run-loop/dispatcher is capable of executing any single opcode, it should be possible to start two copies each in its own thread and dispatch them concurrently.

Heck the all fringe(\$a) Z=== fringe(\$b) alone is crazy enough to require two pages of explanation.

I'm far from expert in P6, but I don't have a problem with that line. The Z=== looks a bit weird, (but so did <=> and =~ etc. when I first came to perl5), but its obviously some form of comparison operator.

all is like the function of the same name in List::MoreUtils. Only true if all the arguments are true, and short-circuiting as soon as the first one is false.

So, if all the fringes of \$a are equal to all the fringes of \$b, the trees are equivalent. Seems clear enough, even if I'd have to look up the details. (I had to do that for the Haskell code; and I often have to do the same for C-runtime routines and the more obscure Perl built-ins.)

With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
This is (I suspect) the intent of the perl6 take/gather "at some future point in time", but currently it take is simply a push to a hidden array and once all the values have been collected, the gather subroutine iterates over that array popping them off as it goes.

This is incorrect. The gather/take implementations in Niecza and Rakudo are lazy and have always been.

It could also be done using green (user space) threading; or continuations; or go-style goroutines. And if you believe the P6 specs, it intends to support all of those and more.

But, when (to my knowledge) there has been no (ZERO) attempt to provide and flavour of multitasking in any of the p6-ish interpreters, it doesn't look likely. YOU cannot add this stuff successfully as an after thought; you have to architect it in from the ground up or you end up with iThreads or similar.

The general framework for P6's concurrency and parallel processing capabilities was designed many years ago. The design wisely abstracts across backends with varying concurrency primitives (CLR, JVM, Parrot, and other VMs). Implementations have then followed this design.

Rakudo was born with usable continuations and coroutines underneath it on day 1 of its existence (because "Parrot is based on continuations"). The threads story is more complex; interested parties would best research for themselves.

"gather/take has controlled the design of Niecza from day 1". Niecza has continuations, coroutines, and threads.

I'd add a note saying something like "While the code looks like the two trees are flattened to lists first and then compared, Haskell is lazy, which means that behind the scenes it will only do as much work as it has to and stop flattening once it finds the first mismatch. Simply don't worry about it. It works."

This is misleading, as it suggests that P6's gather/take is not lazy. Would you be willing to update your comment to fix this mistake?

Update: I was wrong. Apologies to Jenda.