1

I am trying to obtain the first 10 Fibonacci numbers as follows:

(take 10 (fn fibgen [a b] (cons a (fibgen b (+ a b))) 0 1))

The idea is that fibgen creates a lazy sequence (an infinite stream). Unfortunately this gives the following error:

IllegalArgumentException Don't know how to create ISeq from:
user$eval10144$fibgen__10145 clojure.lang.RT.seqFrom (RT.java:528)

How can this be fixed?

user2609980
  • 10,264
  • 15
  • 74
  • 143

1 Answers1

3

I think you just made a typo. Here's what your fibgen function looks like reformatted:

(fn fibgen [a b]
  (cons a (fibgen b (+ a b)))
  0
  1)

This function realizes the entire Fibonacci sequence starting with a and b, then returns 1. What you meant to do was define a function that returns the sequence, call it with 0 and 1, and then take the first ten items from that sequence:

(take 10 ((fn fibgen [a b] (cons a (fibgen b (+ a b)))) 0 1))

If you run this, you'll get an ArithmeticException for integer overflow, because numbers in the Fibonacci sequence quickly leave the range of a 64-bit integer. You can fix this using +':

(take 10 ((fn fibgen [a b] (cons a (fibgen b (+' a b)))) 0 1))

Since Clojure isn't lazy, this will try to realize the entire Fibonacci sequence, which will cause a StackOverflowError. Even though Clojure itself isn't lazy, though, you can create a lazy sequence, which will have basically the same effect in this case:

(take 10 ((fn fibgen [a b] (lazy-seq (cons a (fibgen b (+' a b))))) 0 1))
;;=> (0 1 1 2 3 5 8 13 21 34)
Sam Estep
  • 12,974
  • 2
  • 37
  • 75
  • Thank you. One more question I hope you can answer: if Clojure is not lazy, why does `map` create a lazy seq? See [this earlier question](http://stackoverflow.com/questions/36715935/code-not-called-from-go-block-but-it-works-from-repl#36717600). – user2609980 Jul 02 '16 at 20:54
  • 1
    Clojure is a strict language, which means that values are, by default, stored in a realized form rather than being stored as thunks that are realized only when needed. However, this doesn't mean you can't use thunks; the [`map`](https://github.com/clojure/clojure/blob/clojure-1.8.0/src/clj/clojure/core.clj#L2618-L2665) function uses the [`lazy-seq`](https://github.com/clojure/clojure/blob/clojure-1.8.0/src/clj/clojure/core.clj#L664-L671) macro, which wraps a piece of code into a nullary function and returns an object that will call that function (and cache its result) only when asked to do so. – Sam Estep Jul 02 '16 at 21:16