una tecnica profundimetro profundidad para neumaticos medir medidor llantas llanta indicador desgaste como scala stream lazy-evaluation

tecnica - Scala: ¿las corrientes no son flojas?



profundidad neumaticos revision tecnica (3)

El hecho de que Streams sea flojo no cambia el hecho de que los argumentos del método se evalúan ansiosamente.

Stream(1/0) expande a Stream.apply(1/0) . La semántica del lenguaje requiere que los argumentos se evalúen antes de llamar al método (ya que el método Stream.apply no usa argumentos de llamada por nombre), por lo que intenta evaluar 1/0 para pasar como el argumento al Método Stream.apply , que causa su ArithmeticException.

Sin embargo, hay algunas maneras en que puede hacer que esto funcione. Como ya has declarado bad como un valor lazy val , lo más fácil es usar el operador de concatenación de flujo #::: también-perezoso para evitar forzar la evaluación:

val initial = Stream(1) lazy val bad = Stream(1/0) println((initial #::: bad) take 1) // => Stream(1, ?)

Sé que se supone que las secuencias se evalúan de forma diferida en Scala, pero creo que sufro algún tipo de malentendido fundamental porque parecen estar más ansiosos de lo que hubiera esperado.

En este ejemplo:

val initial = Stream(1) lazy val bad = Stream(1/0) println((initial ++ bad) take 1)

Obtengo una java.lang.ArithmeticException , que parece ser causada por la división cero. Esperaría que nunca se evaluara lo bad ya que solo pedí un elemento de la transmisión. ¿Qué pasa?


The Stream evaluará la cabeza y la cola restante se evaluará de forma perezosa. En su ejemplo, ambas secuencias tienen solo la cabeza y, por lo tanto, dan un error.


OK, entonces, después de comentar otras respuestas, pensé que podría convertir mis comentarios en una respuesta adecuada.

Las transmisiones son de hecho flojas, y solo computarán sus elementos bajo demanda (y usted puede usar #:: para construir un elemento de flujo por elemento, muy similar a :: para List ). Por ejemplo, lo siguiente no arrojará ninguna excepción:

(1/2) #:: (1/0) #:: Stream.empty

Esto se debe a que al aplicar #:: , la cola se pasa por su nombre para no evaluarla ansiosamente, pero solo cuando sea necesario (vea ConsWrapper.# :: , const.apply y clase Cons en Stream.scala para obtener más detalles). Por otro lado, la cabeza se pasa por valor, lo que significa que siempre se evaluará con entusiasmo, sin importar qué (como lo mencionó Senthil). Esto significa que hacer lo siguiente arrojará una ArithmeticException:

(1/0) #:: Stream.empty

Es un gotcha que vale la pena conocer sobre las corrientes. Sin embargo, este no es el problema al que se enfrenta.

En su caso, la excepción aritmética ocurre incluso antes de instanciar una sola transmisión. Al llamar a Stream.apply en lazy val bad = Stream(1/0) , el argumento se ejecuta ansiosamente porque no está declarado como un parámetro por nombre. Stream.apply realidad toma un parámetro vararg, y estos necesariamente pasan por valor. E incluso si se pasara por su nombre, la ArithmeticException se activaría poco después, porque como se dijo anteriormente, el jefe de un Stream siempre se evalúa tempranamente.