po ortogonalmente, questo comportamento può essere realizzato utilizzando coroutines. C'è almeno una libreria per Scala che consente coroutine, si può trovare qui: http://storm-enroute.com/coroutines/
Ecco un esempio del codice potrai scrivere per ottenere ciò che si vuole:
import org.coroutines._
def sideEffectingFunction = coroutine {() =>
val limit = new scala.util.Random().nextInt(10)
val seq = new scala.util.Random
var counter = 0 // mutable state is preserved between coroutine invocations
while (counter < limit) {
counter += 1
yieldval(seq.nextInt)
}
}
defined function sideEffectingFunction
@ val cr = call(sideEffectingFunction())
cr: Coroutine.Frame[Int, Unit] = Coroutine.Frame<depth: 1, live: true>
@ cr.resume
res31: Boolean = true
@ cr.value
res32: Int = 57369026
@ cr.resume
res33: Boolean = true
@ cr.value
res34: Int = -1226825365
@ cr.resume
res35: Boolean = true
@ cr.value
res36: Int = 1304491970
@ cr.resume
res37: Boolean = false
@ cr.value
java.lang.RuntimeException: Coroutine has no value, because it did not yield.
scala.sys.package$.error(package.scala:27)
org.coroutines.Coroutine$Frame$mcI$sp.value$mcI$sp(Coroutine.scala:130)
cmd38$.<init>(Main.scala:196)
cmd38$.<clinit>(Main.scala:-1)
O, in alternativa:
@ val cr = call(sideEffectingFunction())
cr: Coroutine.Frame[Int, Unit] = Coroutine.Frame<depth: 1, live: true>
@ while(cr.resume) println(cr.value)
-1888916682
1135466162
243385373
Oppure, nello spirito della risposta precedente:
@ val cr = call(sideEffectingFunction())
cr: Coroutine.Frame[Int, Unit] = Coroutine.Frame<depth: 1, live: true>
@ cr.resume
res60: Boolean = true
@ val iter = Iterator.continually(cr.value).takeWhile(_ => cr.resume)
iter: Iterator[Int] = non-empty iterator
@ iter.foreach(println)
1595200585
995591197
-433181225
220387254
201795229
754208294
-363238006
T Il vantaggio dell'approccio delle coroutine è che è possibile mantenere uno stato mutabile tra le invocazioni delle funzioni di effetti collaterali sottostanti, tutte ben nascoste dal mondo esterno all'interno di una coroutine. Le coroutine possono anche essere composte e invocate l'un l'altra.
Ovviamente, le coroutine ti danno molta più energia del semplice compito di far funzionare il tuo compito, quindi questo potrebbe essere eccessivo per aggiungerli solo per questo. Tuttavia, è una pratica tecnica da prendere in considerazione.
Mille grazie per una risposta eccellente e tempestiva! – satyagraha
L'ultimo file '.map (_. Get)' può essere sostituito da '.flatten' nelle versioni recenti di Scala, che introduce un implicito TraitableOnce CBF e un iteratore associato. Penso che questo soddisfi ancora i miei criteri. – satyagraha
Hai ragione. Mi è mancato perché lo scaladoc per 'Iterator' non lo menziona. Sembra un errore scaladoc: 'flatten' deriva dalla classe di enrichement' TraversableOnce.FlattenOps' e le distribuzioni dovrebbero essere gestite da scaladoc (e molti lo sono). Ho aggiornato la mia risposta. –