我可以在Clojure中写一个懒惰的斐波那契,就像这样:
(def fib (lazy-cat [1 1] (map +' fib (rest fib))))
我尝试(不成功)用Ruby写这个:
fib = Enumerator.new do |yielder|
yielder << 1 << 1
fib.zip(fib.drop(1)).map do |a,b|
yielder << (a + b)
end
end
在简化的情况下,这有效:
fib = Enumerator.new do |yielder|
yielder << 1 << 1
puts "here"
end
puts fib.take(2).inspect
puts fib.drop(1).take(1).inspect
但这并不是:
fib = Enumerator.new do |yielder|
yielder << 1 << 1
puts "here"
fib.drop(1)
end
puts fib.take(2).inspect
puts fib.drop(1).take(1).inspect
为什么最后一个例子给我一个SystemStackError: stack level too deep
错误?
答案 0 :(得分:3)
首先,ruby版本中的fib
不等同于clojure版本。在clojure版本中,它是一个功能。
除非您明确指定,否则Enumerable#zip
,Enumerable#drop
和Enumerable.take
不会延迟。如果你不调用Enumerable#lazy
,他们会返回一个数组(急切地消耗所有项目;引起异常)。
def fib
Enumerator.new do |yielder|
yielder << 1 << 1
fib.lazy.zip(fib.lazy.drop(1)).each do |a,b|
yielder << a + b
end
end
end
fib.take(2)
# => [1, 1]
fib.lazy.drop(1).take(1).to_a # Note: `lazy`, `to_a`.
# => [1]
fib.take(4)
# => [1, 1, 2, 3]