22

I've been looking at the various ways of constructing lazy lists in Perl 6 and I would like to collect all of the concise ways of describing the Fibonacci sequence.

I will start this off with the three from masak's journal:

my @fibs := (0, 1, -> $a, $b { $a + $b } ... *);

my @fibs := (0, 1, { $^a + $^b } ... *);  

my @fibs := (0, 1, *+* ... *);

I was thinking something like this would also work, but I think I have the syntax wrong:

my @fibs := (0, 1, (@fibs Z+ @fibs[1..*]));

Something there is eager (the slice?) and causes Rakudo to enter an infinite loop. It's a translation of the Haskell definition:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

Update:

Seems like the problem with the zipWith example is the @fibs[1..*] slice. if tail is defined as sub tail (@x) {my $i = 1; {@x[$i++]}...*} then it works properly. I would be interested to know why the slice isn't lazy from anyone familiar with Rakudo's internals.

Another nice one is:

my @fibs := (0, [\+] 1, @fibs);
Pat
  • 36,282
  • 18
  • 72
  • 87
Eric Strom
  • 39,821
  • 2
  • 80
  • 152
  • 3
    This is one of the reasons I like Perl 6. :) – brian d foy Oct 20 '10 at 22:13
  • Is the question about your bug, or about possible other solutions? Your code is missing a closing parenthesis, if Perl 6's syntax isn't stranger than I thought... – Charles Stewart Oct 21 '10 at 08:18
  • Have you tried your code on Pugs? – Charles Stewart Oct 21 '10 at 08:20
  • @Charles => Thanks for catching the paren, fixed. That was just a typo when I wrote the question. I would like to collect all of the different ways to write the sequence. I posted the zipWith solution as one that I think should be doable, but that I have not had success with. I have not tried to run these in Pugs. – Eric Strom Oct 21 '10 at 15:47

2 Answers2

4

The shortest seems to be

my @fibs := ^2,*+*...*;
Pat
  • 36,282
  • 18
  • 72
  • 87
0

You can use the magic of the golden ratio: let φ=(sqrt(5)+1)/2, and define fib(n)=(φn+(1-φ)n)/sqrt(5).

You can convert such a function into a lazy list in the obvious way: In Haskell the following works:

fibs=genfibs 0 where genfibs n=(round (fib n)):genfibs (n+1)

I'm afraid my Perl 6 knowledge isn't up to translating this, sorry! Anyone who edits this answer to edit in the codes will earn my gratitude.

A more testing question would be to list ways of generating the lazy list of Hamming numbers.

Charles Stewart
  • 11,661
  • 4
  • 46
  • 85
  • 1
    Sorry to be pedantic, but for clarification: the golder ratio is 0.5*(sqrt(5)+1) and the closed form of a fibonacci number is ((1+sqrt(5))^n - (1-sqrt(5))^n)/(2^n * sqrt(5)) = (φ^n-(1-φ)^n)/sqrt(5) [http://mathworld.wolfram.com/FibonacciNumber.html] – Phil Oct 22 '10 at 15:47
  • 1
    @Phil: Yes, I should have checked, at least that case n=0 worked. Far from a pedantic correction; many thanks. – Charles Stewart Oct 23 '10 at 07:07
  • 2
    A way to turn such a function to a lazy list in Perl 6 is `my @fibs = ->{ fib $++ } ... *`. I don't think what you have can be easily translated directly to Perl 6 as functions are not normally lazy. `$ perl6 -e 'constant φ = (sqrt(5)+1)/2; sub fib (\n) { (φ**n - (1-φ)**n)/sqrt(5) }; my @fibs = ->{ round fib $++ } ... *; say @fibs'`, although that starts getting incorrect results after the first 70 results because of floating point errors. ( I have gotten more correct numbers with FatRats, but that slows the calculations down considerably ) – Brad Gilbert Apr 16 '15 at 02:03