Clojure 函数局部、自参考、惰性斐波那契序列
我想创建一个函数,返回一个延迟扩展的Fibonacci数的无限序列 现在,我可以在顶级名称空间中使用我的序列,如下所示:Clojure 函数局部、自参考、惰性斐波那契序列,clojure,fibonacci,local-variables,Clojure,Fibonacci,Local Variables,我想创建一个函数,返回一个延迟扩展的Fibonacci数的无限序列 现在,我可以在顶级名称空间中使用我的序列,如下所示: (def fibonacci-numbers (lazy-cat [0 1] (map + fibonacci-numbers (rest fibonacci-numbers)))) 然而,这意味着,如果我开始大量使用它们,我将失去对垃圾收集的控制 我希望做一些类似的事情: (defn fibonacci-numbers-fn [] (lazy-cat [0 1]
(def fibonacci-numbers
(lazy-cat [0 1] (map + fibonacci-numbers (rest fibonacci-numbers))))
然而,这意味着,如果我开始大量使用它们,我将失去对垃圾收集的控制
我希望做一些类似的事情:
(defn fibonacci-numbers-fn []
(lazy-cat [0 1] (map + (fibonacci-numbers-fn) (rest (fibonacci-numbers-fn)))))
这显然行不通,因为我最终将创建O(2^n)序列。我想我是在问如何在函数本地名称空间中创建一个自引用惰性序列。我该怎么办
编辑:虽然我喜欢amalloy发布的流行解决方案,并且在互联网上到处都可以找到defn fibs[](映射优先(迭代(fn[[ab]]][b(+ab)])[01]))
,但我对类似于规范的Haskell方式的版本感兴趣:
fibonaccis = 0 : 1 : zipWith (+) fibonaccis (tail fibonaccis)
这就是我试图用我的原始函数来完成的。对我来说,map iterate解决方案的内容类似于“添加前两个元素以创建一个新元素”,而lazy cat解决方案的内容类似于“加入一个具有第一个延迟的流”。我如何才能在顶级名称空间中没有序列的情况下“加入具有第一个延迟的流”?也许
letfn
就是您要寻找的
(def fibo-nums
(letfn [(fibo-num-fn []
(lazy-cat [0 1]
(map + (fibo-num-fn) (rest (fibo-num-fn)))))]
fibo-num-fn))
或者,如果您打算手工使用lazy seq:
(letfn [(fibs
([]
(fibs 0 1))
([a b]
(lazy-seq
(cons a (fibs b (+ a b))))))]
(take 10 (fibs)))
;; (0 1 1 2 3 5 8 13 21 34)
如果将可选名称放在[]之前,则由
fn
表单定义的函数可以是递归函数。(在本例中,使用的名称为this
)
产生序列的实际函数是匿名函数,每次调用它时只产生下一个元素。没有堆栈或堆溢出的可能性(除非您将封闭函数的返回值保存在某个var中)您可以使用
承诺来解决问题,手动执行haskell自动执行的操作:
(defn fibs []
(let [fibs (promise)]
@(doto fibs
(deliver (list* 0 1 (lazy-seq (map +' @fibs (rest @fibs))))))))
我遇到了一个非常类似的问题,最终选择了以下宏(这基本上比amalloy关于承诺的回答更重要):
这样,您就可以编写:
(defn fibonacci-numbers-fn []
(rec-seq fibs (lazy-cat [0 1] (map +' fibs (rest fibs)))))
这几乎就是你想写的
注:rec-seq是递归seq的缩写。您的defn
需要[]
,但我不想进行两个字符的编辑<代码>(╯°□°)╯︵ ┻━┻代码>如果你走这条路,我想你最终会遇到我上面提到的同样的问题;您不断调用该函数并创建新序列。有人能证实吗?我认为您也缺少了一个[]
,需要在最后调用fibo num fn,而不是返回函数本身:)。嗯,我想我不完全理解您的问题。这是一个很好的解决最初提出的问题的方法。你能想出一种方法让代码按照我的编辑方式阅读吗?
(defn fibs []
(let [fibs (promise)]
@(doto fibs
(deliver (list* 0 1 (lazy-seq (map +' @fibs (rest @fibs))))))))
(defmacro rec-seq [name expr]
`(let [p# (promise)
s# (lazy-seq (let [~name @p#] ~expr))]
(deliver p# s#)
s#))
(defn fibonacci-numbers-fn []
(rec-seq fibs (lazy-cat [0 1] (map +' fibs (rest fibs)))))