【问题标题】:Generate first 10 Fibonacci numbers using infinite stream使用无限流生成前 10 个斐波那契数
【发布时间】:2016-07-02 19:05:28
【问题描述】:
我正在尝试获取前 10 个斐波那契数,如下所示:
(take 10 (fn fibgen [a b] (cons a (fibgen b (+ a b))) 0 1))
这个想法是fibgen 创建一个惰性序列(无限流)。不幸的是,这给出了以下错误:
IllegalArgumentException 不知道如何从以下位置创建 ISeq:
user$eval10144$fibgen__10145 clojure.lang.RT.seqFrom (RT.java:528)
如何解决这个问题?
【问题讨论】:
标签:
clojure
fibonacci
lazy-sequences
【解决方案1】:
我想你只是打错字了。这是您的 fibgen 函数重新格式化后的样子:
(fn fibgen [a b]
(cons a (fibgen b (+ a b)))
0
1)
这个函数实现了从a和b开始的整个斐波那契数列,然后返回1。你的意思是定义一个返回数列的函数,调用它用0和1,然后从该序列中取出前十项:
(take 10 ((fn fibgen [a b] (cons a (fibgen b (+ a b)))) 0 1))
如果你运行这个,你会得到一个整数溢出的ArithmeticException,因为斐波那契数列中的数字很快就会离开一个 64 位整数的范围。您可以使用+' 解决此问题:
(take 10 ((fn fibgen [a b] (cons a (fibgen b (+' a b)))) 0 1))
由于 Clojure 不是惰性的,这将尝试实现整个斐波那契数列,这将导致 StackOverflowError。尽管 Clojure 本身并不懒惰,但您可以创建一个 lazy sequence,在这种情况下它的效果基本相同:
(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)
【讨论】:
-
谢谢。还有一个问题希望你能回答:如果 Clojure 不是惰性的,为什么map 会创建惰性序列?见this earlier question。
-
Clojure 是一种严格的语言,这意味着默认情况下,值以实现的形式存储,而不是存储为仅在需要时才实现的 thunk。但是,这并不意味着您不能使用 thunk。 map 函数使用 lazy-seq 宏,它将一段代码包装到一个空函数中,并返回一个对象,该对象仅在被要求时才会调用该函数(并缓存其结果)。