2010-05-14 12 views

Respuesta

7

En 2.8, hay un método protegido llamado tailDefined que devolverá falso cuando llegue al punto en la secuencia que aún no se ha evaluado.

Esto no es demasiado útil (a menos que desee escribir su propia clase Stream), excepto que Cons hace que el método sea público. No estoy seguro de por qué está protegido en Stream y no en Cons. Creo que uno o el otro podría ser un error. Pero por ahora, al menos, se puede escribir un método como tal (escribir un equivalente funcional se deja como ejercicio para el lector):

def streamEvalLen[T](s: Stream[T]) = { 
    if (s.isEmpty) 0 
    else { 
    var i = 1 
    var t = s 
    while (t match { 
     case c: Stream.Cons[_] => c.tailDefined 
     case _ => false 
    }) { 
     i += 1 
     t = t.tail 
    } 
    i 
    } 
} 

Aquí puede verlo en acción:

scala> val s = Stream.iterate(0)(_+1) 
s: scala.collection.immutable.Stream[Int] = Stream(0, ?) 

scala> streamEvalLen(s) 
res0: Int = 1 

scala> s.take(3).toList 
res1: List[Int] = List(0, 1, 2) 

scala> s 
res2: scala.collection.immutable.Stream[Int] = Stream(0, 1, 2, ?) 

scala> streamEvalLen(s) 
res3: Int = 3 
+0

El método 'tailDefined' es público en ambos' Contras' y 'Empty', así que no creo que sea un error. No me di cuenta de eso antes. Puedo adaptar tu solución para resolver mi problema. –

3

Escriba esa declaración en el shell interactivo y verá que se evalúa como s: Stream[Int] = Stream(1, ?). Entonces, de hecho, los otros dos elementos de 2 y 3 aún no se conocen.

Al acceder a otros elementos, se calcula una mayor cantidad de la secuencia. Por lo tanto, ahora ponga s(3) en el shell, que devolverá res0: Int = 2. Ahora ponga s en el shell y verá el nuevo valor res1: Stream[Int] = Stream(1, 2, 3, 2, ?).

El único método que pude encontrar que contenía la información que deseaba era, desafortunadamente, s.toString. Con algunos análisis, podrás recuperar los elementos de la cadena. Esta es una solución apenas aceptable con solo entradas y no podía imaginar ninguna solución genérica usando la idea de análisis de cadenas.

5

La solución basada en Rex's answer:

def evaluatedItems[T](stream: => Stream[T]): List[T] = { 
    @tailrec 
    def inner(s: => Stream[T], acc: List[T]): List[T] = s match { 
    case Empty => acc 
    case c: Cons[T] => if (c.tailDefined) { 
     inner(c.tail, acC++ List(c.head)) 
    } else { acC++ List(c.head) } 
    } 
    inner(stream, List()) 
} 
0

Usando scanLeft

lazy val s: Stream[Int] = 1 #:: s.scanLeft(2) { case (a, _) => 1 + a } 
Cuestiones relacionadas