There’s been some discussion on reddit today about whether
my @fib := 1, 1, *+* ...^ * >= 100;
is unreadable gibberish or not, with the following Haskell suggested as an easier-to-understand version.
fib = 1 : 1 : zipWith (+) fib (tail fib)
(I’ve “corrected” both versions so they start the sequence with 1, 1.)
The first thing to observe here is that this are not the same at all! The Perl 6 version is the Fibonacci numbers less than 100, while the Haskell version lazily generates the entire infinite sequence. If we simplify the Perl 6 to also be the (lazy) infinite Fibonacci sequence, we get the noticeably simpler
my @fib := 1, 1, *+* ... *;
To my (admittedly used to Perl 6) eye, this sequence is about as clean and straightforward as it is possible to get. We have the first two elements of the sequence:
We have the operation to apply repeatedly to get the further elements of the sequence:
And we are told the sequence will go on forever:
*+* construct may be unfamiliar to people who aren’t Perl 6 programmers, but I hardly think it is more conceptually difficult than referring to two recursive copies of the sequence you are building, as the Haskell version does. Instead, it directly represents the simple understanding of how to get the next element in the Fibonacci sequence in source code.
Of course, this being Perl, there is more than one way to do it. Here’s a direct translation of the Haskell version into idiomatic Perl 6:
my @fib := 1, 1, (@fib Z+ @fib[1..*]);
Well, allowing the use of operators and metaoperators, that is, as
zipWith (+) becomes
tail fib becomes
@fib[1..*]. To the best of my knowledge no current Perl 6 implementation actually supports this. I’d be surprised if any Perl 6 programmer would prefer this version, but it is out there.
If you’re insistent on writing function calls instead of operators, you could also say it
my @fib := 1, 1, zipwith(&[+], @fib, tail(@fib));
presuming you write a
tail function, but that’s an easy one-liner.