1
votes

I am new to Clojure and Lisp, but love it so far. I am currently trying to understand lazy-seq's and Clojure's ability to define infinite sequences. I have the following code:

(defn geometric
  ([] geometric 1)
  ([n] (cons n (lazy-seq (geometric (* n 1/2))))))

If I run:

(geometric)

in my REPL, it returns 1, as expected. However, if I run,

(take 10 (geometric))

I get the following error:

IllegalArgumentException Don't know how to create ISeq from:
java.lang.Long  clojure.lang.RT.seqFrom

What I expect to get is:

(1 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256 1/512)

Why am I getting this error? If I've understood correctly, one should be able to cons n to the lazy-sequence, and take should return the first ten values of the sequence, evaluated recursively.

4

4 Answers

4
votes

One of my favorite functions: iterate takes a function f and a value x returning x, (f x), (f (f x), (f (f (f x))) etc.

Here is an elegant implementation with the same functionality:

(defn geometric []
  (iterate #(/ % 2) 1))

Not a direct answer to your question but hopefully informative!

2
votes

You have a small typo in your code:

(defn geometric
  ([] (geometric 1)) ;; notice the added parens around geometric 1
  ([n] (cons n (lazy-seq (geometric (* n 1/2))))))

Without this fix (geometric 1) was working because the implementation was to evaluate expression geometric (just a function value) which was discarded, then 1 expression was evaluated and returned as the function result (it was the last expression in this arity function body).

Now it works as expected:

(take 1 (geometric))
;; => (1)

(take 5 (geometric))
;; => (defn geometric
  ([] geometric 1)
  ([n] (cons n (lazy-seq (geometric (* n 1/2))))))

Notice that you cannot just call (geometric) safely in REPL as it will try to evaluate an infinite sequence.

2
votes

Your problem is here:

([] geometric 1)

This expression means that, if geometric is called with no arguments, two things will happen:

  1. The symbol geometric will be evaluated, which will result in the geometric function.
  2. The number 1 will be returned.

What you probably meant was this:

([] (geometric 1))

This means that calling (geometric) is equivalent to calling (geometric 1). Your example will now work as expected:

(take 10 (geometric))
;=> (1 1/2 1/4 1/8 1/16 1/32 1/64 1/128 1/256 1/512)
1
votes

(geometric) evaluates to the number 1, not to a sequence. (take 10 1) gives the same error that you're seeing now.

You should try running (take 10 (geometric 1)), since (geometric 1) will produce a sequence which can be supplied to the second argument of take.