Dato il seguente codice:Reverse lista Scala
import scala.util.Random
object Reverser {
// Fails for big list
def reverseList[A](list : List[A]) : List[A] = {
list match {
case Nil => list
case (x :: xs) => reverseList(xs) ::: List(x)
}
}
// Works
def reverseList2[A](list : List[A]) : List[A] = {
def rlRec[A](result : List[A], list : List[A]) : List[A] = {
list match {
case Nil => result
case (x :: xs) => { rlRec(x :: result, xs) }
}
}
rlRec(Nil, list)
}
def main(args : Array[String]) : Unit = {
val random = new Random
val testList = (for (_ <- 1 to 2000000) yield (random.nextInt)).toList
// val testListRev = reverseList(testList) <--- Fails
val testListRev = reverseList2(testList)
println(testList.head)
println(testListRev.last)
}
}
Perché la prima versione della funzione fallisce (per i grandi ingressi), mentre la seconda variante funziona. Sospetto che si tratti di una ricorsione in coda, ma non ne sono molto sicuro. Qualcuno può darmi una spiegazione "per principianti"?
Perché non utilizzare 'val testListRev = testList.reverse'? – Lutz
Questa domanda è stata posta molto tempo fa, ma ecco la risposta alla tua domanda sulla ricorsione in coda. Sì, è a causa dell'ottimizzazione della ricorsione della coda. Nella tua prima implementazione, caso (x :: xs) => reverseList (xs) ::: List (x), dopo aver chiamato reverseList in modo ricorsivo, il programma deve aggiungere List (x) ad esso. Ciò significa che non può essere ottimizzato in un ciclo, nel tuo secondo esempio: case (x :: xs) => {rlRec (x :: result, xs)} rlRec è l'ultima chiamata, niente da fare dopo la sua uscita e questo è il motivo per cui non deve creare un nuovo frame Stack per questo. – loteq