【问题标题】:Scala stream behaves counterintuitiveScala 流的行为违反直觉
【发布时间】:2013-07-25 20:25:45
【问题描述】:

我正在玩 Scala 的流,但我不确定我是否明白这个想法。 让我们考虑以下代码

def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head, fun(s.tail))

执行这个

val f = fun(Stream.from(7))
f take 14 foreach println

结果

7 8 9 10 ... up to 20

假设我明白这一点。

现在,稍微改变一下代码(在头部添加 2)

def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head + 2, fun(s.tail))

结果

9 10 11 ... up to 22

再次,我想我明白了。问题从下一个例子开始(d

def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head / 2, fun(s.tail))

3 4 4 5 5 6 6 7 7 8 8 9 9 10

这个我不明白,请解释为什么会这样? 类似地,减法也不像我预期的那样表现

def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head - 2, fun(s.tail))

输出

5 6 7 8 9 10 ... up to 18

【问题讨论】:

  • 对我来说似乎很正常。您为什么不尝试解释一下您的预期与您得到的,以便有人可以尝试帮助您解决断开连接的位置。

标签: scala stream


【解决方案1】:

鉴于你的“接受”:7 8 9 10 ... up to 20,

  • 当您在每个元素上+ 2 时会发生什么?

  • 当你在每个元素上/ 2 时会发生什么(int 算术)?

  • 当您在每个元素上- 2 时会发生什么?

【讨论】:

    【解决方案2】:

    如果你把它想象成映射Stream会更直观吗?

    scala> val s1 = Stream.from(10)
    s1: scala.collection.immutable.Stream[Int] = Stream(10, ?)
    
    scala> val s2 = s1 map (_ * 2)
    s2: scala.collection.immutable.Stream[Int] = Stream(20, ?)
    
    scala> s2.take(5).toList
    res0: List[Int] = List(20, 22, 24, 26, 28)
    
    scala> val s3 = s1 map (_ / 2)
    s3: scala.collection.immutable.Stream[Int] = Stream(5, ?)
    
    scala> s3.take(5).toList
    res1: List[Int] = List(5, 5, 6, 6, 7)
    
    scala> val s4 = s1 map (_ - 2)
    s4: scala.collection.immutable.Stream[Int] = Stream(8, ?)
    
    scala> s4.take(5).toList
    res2: List[Int] = List(8, 9, 10, 11, 12)
    

    【讨论】:

      【解决方案3】:

      好吧,让我们试着分解一下……

      def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head, fun(s.tail))
      

      是一个函数,它接受 Stream 并将其 headtail 分开,递归地将自身应用于 tail,然后使用 cons 运算符重新组合这两个结果。

      由于在此操作期间未触及head,因此Stream 会像以前一样逐个元素地重建。

      val f = fun(Stream.from(7))
      

      fStream.from(7) 相同 [即从 7 开始的无限递增整数序列]

      打印 f take 14 实际上表明我们有 从 7 开始的前 14 个数字 [即7,8,9,...,20]

      接下来发生的事情是,在使用cons 重建流时,每个元素都会以某种方式进行修改

      def fun(s: Stream[Int]): Stream[Int] = Stream.cons(s.head + 2, fun(s.tail))
      

      将 2 添加到 head,然后将其与修改后的 tail 重新组合。后者以同样的方式修改,它的第一个元素被添加到2,然后重新组合到它自己的tail,因此拥有。

      如果我们再次假设 s 包含从 7 开始的数字,会发生什么

      fun(s) = cons(7 + 2, cons(8 + 2, cons(9 + 2, ... ad infinitum ... )))))
      

      这与在流 s 的每个元素上加 2 相同。

      代码通过打印“9 到 22”来确认这一点,这正是“7 到 20”,每个元素都添加了 2。

      其他例子类似:

      • 每个元素的流除以 2(四舍五入到地板 整数值,因为Stream 是用Int 值输入的)
      • 每个元素递减 2 的流

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-29
        • 1970-01-01
        • 2016-07-05
        • 2020-03-21
        • 1970-01-01
        • 2017-07-22
        • 2011-05-30
        相关资源
        最近更新 更多