Por lo tanto, estoy trabajando para enseñarme Scala, y una de las cosas con las que he estado jugando es la clase Stream
. Traté de usar una traducción ingenua de la classic Haskell version of Dijkstra's solution al problema del número de Hamming:Coincidencia de patrones y flujos infinitos
object LazyHammingBad {
private def merge(a: Stream[BigInt], b: Stream[BigInt]): Stream[BigInt] =
(a, b) match {
case (x #:: xs, y #:: ys) =>
if (x < y) x #:: merge(xs, b)
else if (y < x) y #:: merge(a, ys)
else x #:: merge(xs, ys)
}
val numbers: Stream[BigInt] =
1 #:: merge(numbers map { _ * 2 },
merge(numbers map { _ * 3 }, numbers map { _ * 5 }))
}
Teniendo esto para dar una vuelta en el intérprete llevó rápidamente a la decepción:
scala> LazyHammingBad.numbers.take(10).toList
java.lang.StackOverflowError
que decidí mirar para ver si otras personas se habían resuelto el problema en Scala utilizando el enfoque de Haskell, y adaptado this solution del Código de Rosetta:
object LazyHammingGood {
private def merge(a: Stream[BigInt], b: Stream[BigInt]): Stream[BigInt] =
if (a.head < b.head) a.head #:: merge(a.tail, b)
else if (b.head < a.head) b.head #:: merge(a, b.tail)
else a.head #:: merge(a.tail, b.tail)
val numbers: Stream[BigInt] =
1 #:: merge(numbers map {_ * 2},
merge(numbers map {_ * 3}, numbers map {_ * 5}))
}
Ésta Funcionó muy bien, pero todavía me pregunto cómo me equivoqué en LazyHammingBad
. ¿El uso de #::
para desestructurar x #:: xs
fuerza la evaluación de xs
por algún motivo? ¿Hay alguna forma de utilizar la coincidencia de patrones de forma segura con flujos infinitos, o simplemente tiene que usar head
y tail
si no desea que las cosas exploten?
estoy usando 'solución val perezoso: Listado [Mover] = {pathsToGoal partido caso (_, moveHistory) # :: _ => moveHistory.reverse funda _ => List.empty [Mover] }' y esto no evalúa la cola. ¿Es porque estoy usando _? Aquí en este caso pathsToGoal es un flujo infinito – himanshu219