【问题标题】:How to fix my Fibonacci stream in Scala如何在 Scala 中修复我的斐波那契流
【发布时间】:2012-01-29 08:32:36
【问题描述】:

我定义了一个函数来返回斐波那契流如下:

def fib:Stream[Int] = {
  Stream.cons(1,
    Stream.cons(2,
      (fib zip fib.tail) map {case (x, y) => println("%s + %s".format(x, y)); x + y}))
}

功能正常,但看起来效率低下(见下面的输出)

scala> fib take 5 foreach println
1
2
1 + 2
3
1 + 2
2 + 3
5
1 + 2
1 + 2
2 + 3
3 + 5
8

所以,看起来函数从一开始就计算了第 n 个斐波那契数。这是正确的吗?你会如何解决它?

【问题讨论】:

    标签: scala stream fibonacci


    【解决方案1】:

    那是因为您使用了def。尝试使用val

    lazy val fib: Stream[Int] 
      = 1 #:: 2 #:: (fib zip fib.tail map { case (x, y) => x + y })
    

    基本上def 是一种方法;在您的示例中,您每次都调用该方法,并且每次该方法调用构造一个新流时。 defval的区别有been covered on SO before,这里不再赘述。如果你是Java背景的,应该很清楚。

    这是 scala 的另一个优点;在 Java 中,方法可能是递归的,但类型和值可能不是。在 Scala 中,值和类型都可以是递归的。

    【讨论】:

    • 谢谢。有趣的是,如何编写一个函数来返回一个斐波那契流?
    • 你已经写过一篇了;但是您每次都返回流的不同实例。因为 scala 有副作用,所以运行时不能用单个延迟计算的值替换表达式
    • 好的。如果我需要一个带参数的函数怎么办:例如fib(f1:Int, f2:Int):Stream[Int],其中f1f2 是序列的第一个和第二个数字?
    • Scala 不是一种引用透明的语言。运行时不会“缓存”对您的方法的调用。如果你不想每次都构造一个新的流,要么记住结果,要么在本地提取到一个 val 中。
    • 您如何看待def fib(f1:Int, f2:Int):Stream[Int] = Stream.cons(f1, fib(f1, f1 + f2)) 如下回复?看起来很有效率。
    【解决方案2】:

    您可以通过其他方式进行操作:

    
    lazy val fibs = {
      def f(a: Int, b: Int): Stream[Int] = a #:: f(b, a + b)
      f(0, 1)
    }
    

    【讨论】:

    • 外面的应该只是一个def。然后,您可以精确控制返回的流,并能够在需要时删除该引用。例如,如果您只想要一个以第 100,000 个 fib 数字开头的流,那么您可以使用 val bigs = fibs drop 100000 take n,而 bigs 不会在内存中保存前 100000 个。
    猜你喜欢
    • 1970-01-01
    • 2016-08-02
    • 2016-04-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多