Ho una funzione ricorsiva che sto cercando di rendere @tailrec
facendo in modo che la parte interna ricorsiva (countR3
) aggiunga elementi a una coda (agenda
è un scala.collections.mutable.Queue
). La mia idea è quella di far passare la parte esterna della funzione sull'agenda e riassumere i risultati.C'è un modo elegante per piegarsi su un crescente scala.collections.mutable.Queue?
NOTA: Questo era un problema di compiti a casa, quindi non voglio postare l'intero codice; tuttavia, l'implementazione della coda ricorsiva era non parte dei compiti.
Ecco la parte del codice relativo alla mia domanda:
import scala.collection.mutable.Queue
val agenda: Queue[Tuple2[Int, List[Int]]] = Queue()
@tailrec
def countR3(y: Int, x: List[Int]): Int = {
if (y == 0) 1
else if (x.isEmpty) 0
else if …
else {
agenda.enqueue((y - x.head, x))
countR3(y, x.tail)
}
}
⋮
agenda.enqueue((4, List(1, 2)))
val count = agenda.foldLeft(0) {
(count, pair) => {
val mohr = countR3(pair._1, pair._2)
println("count=" + count + " countR3=" + mohr)
count + mohr
}
}
println(agenda.mkString(" + "))
count
Questo quasi sembra funzionare ... Il problema è che non un'iterazione su tutti gli elementi aggiunti all'ordine del giorno, ancora processa alcuni di di loro. Si può vedere questo nell'output di seguito: [. Dei sei punti all'ordine del giorno finale, solo i primi tre sono stati elaborati]
count=0 countR3=0
count=0 countR3=0
count=0 countR3=0
(4,List(1, 2)) + (3,List(1, 2)) + (2,List(2)) + (2,List(1, 2)) + (1,List(2)) + (0,List(2))
Sono generalmente ben consapevoli dei pericoli di mutanti una raccolta mentre stai iterando su di essa, per esempio, su Java. Ma una coda è una specie di cavallo di un colore diverso. Certo, capisco che potrei semplicemente scrivere un ciclo imperativo, in questo modo:
var count = 0
while (!agenda.isEmpty) {
val pair = agenda.dequeue()
count += countR3(pair._1, pair._2)
}
Questo funziona perfettamente bene, ma essendo questo Scala, sto esplorando per vedere se c'è un funzionalmente elegante modo più.
Qualche suggerimento?
Non esattamente idiomatico, sarei d'accordo, ma sembra che sarebbe adatto al fatto di essere più funzionalmente puri. Bella risposta! E, interessante, l'agenda.foldLeft' stava elaborando più che solo gli articoli inizialmente accatastati; non sembra che stia semplicemente lavorando su una copia della coda iniziale. Forse si stava fermando quando l'elemento "ultimo" ha comportato l'aggiunta di altri elementi alla coda, o qualcosa del genere. –