【问题标题】:Lazy fibonacci in RubyRuby中的懒惰斐波那契
【发布时间】:2014-10-03 04:07:59
【问题描述】:

我可以像这样在 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 错误?

【问题讨论】:

  • drop 是一个基于枚举器的函数。尝试通过索引以老式方式访问枚举器内的元素。

标签: ruby clojure fibonacci lazy-sequences


【解决方案1】:

首先,ruby 版本中的fib 不等同于clojure 版本。在 clojure 版本中,它是一个函数。

除非您明确指定,否则 Enumerable#zipEnumerable#dropEnumerable.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]

【讨论】:

  • 哇,你需要在那里使用.lazy,这让我很惊讶。上面的 Clojure 代码创建了一个 var 并像这样使用:(take 2 (drop 1 fib))。将使用defn 创建一个函数。感谢您的回答——正是我想要的!
  • 也许对效率低下的警告会很好。 fib.take(20) 已经用 can't create fiber (FiberError) 为我崩溃了。顺便说一句,我是从new question using this 来到这里的。
猜你喜欢
  • 1970-01-01
  • 2018-07-07
  • 2017-12-12
  • 2014-09-10
  • 2018-10-08
  • 1970-01-01
  • 2012-08-24
  • 2012-12-29
  • 1970-01-01
相关资源
最近更新 更多