Beginner Clojurist Lazy Sequence error: Don't know how to create ISeq from: java.lang.Long

Beginner Clojurist Lazy Sequence error: Don't know how to create ISeq from: java.lang.Long

我是 Clojure 和 Lisp 的新手,但到目前为止很喜欢。我目前正在尝试了解 lazy-seq 和 Clojure 定义无限序列的能力。我有以下代码:

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

如果我运行:

(geometric)

在我的 REPL 中,它 returns 1,正如预期的那样。但是,如果我 运行,

(take 10 (geometric))

我收到以下错误:

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

我期望得到的是:

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

为什么会出现此错误?如果我理解正确,应该能够对惰性序列进行 cons n 处理,并且应该 return 序列的前十个值,递归计算。

您的代码中有一个小错字:

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

没有这个修复 (geometric 1) 是有效的,因为实现是评估被丢弃的表达式 geometric(只是一个函数值),然后 1 表达式被评估并作为函数结果(它是这个 arity 函数体中的最后一个表达式)。

现在它按预期工作了:

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

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

请注意,您不能在 REPL 中安全地调用 (geometric),因为它会尝试计算无限序列。

(geometric) 的计算结果为数字 1,而不是序列。 (take 10 1) 给出与您现在看到的相同的错误。

你应该尝试 运行 (take 10 (geometric 1)),因为 (geometric 1) 会产生一个序列,可以提供给 take 的第二个参数。

你的问题在这里:

([] geometric 1)

这个表达式意味着,如果不带参数调用 geometric,将发生两件事:

  1. 将计算符号 geometric,这将导致 geometric 函数。
  2. 将返回号码1

你的意思可能是这样的:

([] (geometric 1))

这意味着调用(geometric)等同于调用(geometric 1)。您的示例现在将按预期工作:

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

我最喜欢的函数之一:iterate 接受函数 f 和值 x 返回 x, (f x), (f (f x), (f (f (f x)))

这是一个具有相同功能的优雅实现:

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

不是对您问题的直接回答,但希望能提供信息!