La maggior parte dei linguaggi funzionali utilizza elenchi collegati come struttura dati immutabile primaria. Perché elenchi e non ad esempio alberi? Gli alberi possono anche riutilizzare percorsi e persino elenchi di modelli.
La maggior parte dei linguaggi funzionali utilizza elenchi collegati come struttura dati immutabile primaria. Perché elenchi e non ad esempio alberi? Gli alberi possono anche riutilizzare percorsi e persino elenchi di modelli.
Risposte:
Perché gli elenchi sono più semplici degli alberi. (Puoi vederlo in modo banale dal fatto che un elenco è un albero degenerato, in cui ogni nodo ha un solo figlio.)
L'elenco di contro è la struttura di dati ricorsiva più semplice possibile di dimensioni arbitrarie.
Guy Steele ha sostenuto durante la progettazione del linguaggio di programmazione della Fortezza che per i calcoli massicciamente paralleli del futuro, sia le nostre strutture di dati che il nostro flusso di controllo dovrebbero essere a forma di albero con più rami, non lineari come sono ora. Ma per il momento, la maggior parte delle librerie della nostra struttura di dati di base sono state progettate con elaborazione sequenziale e iterativa (o ricorsione della coda, non importa, sono la stessa cosa) in mente, non elaborazione parallela.
Si noti che ad esempio in Clojure, le cui strutture di dati sono state progettate specificamente per il mondo parallelo, distribuito e "nuvoloso" di oggi, anche gli array (chiamati vettori in Clojure), probabilmente la struttura di dati più "lineare" di tutti, sono effettivamente implementati come alberi.
Quindi, in breve: un elenco di contro è la struttura di dati ricorsiva persistente più semplice possibile e non è stato necessario scegliere un "default" più complicato. Altri sono ovviamente disponibili come opzioni, ad esempio Haskell ha array, code di priorità, mappe, cumuli, passaggi, tentativi e tutto ciò che si può immaginare, ma il valore predefinito è la semplice lista di contro.
data Tree a = Leaf a | Branch a (Tree a) (Tree a)
. Ciò rafforza il tuo argomento "semplicità".
Sequence
o Scala Vector
), ma non usano gli alberi quando hanno bisogno di leggere solo perché possono raggiungerlo in tempo reale costante (es. Haskell's Vector
o F # via .Net's ImmutableArray
)
pmap
ping su un vettore in Clojure accede ancora ad ogni elemento in sequenza; la struttura ad albero del vettore è generalmente nascosta all'utente finale.
In realtà, quelle liste sono alberi! Hai nodi con due campi car
e cdr
, che possono contenere più di tali nodi o foglie. L'unica cosa che trasforma quegli alberi in elenchi è la convenzione di interpretare il cdr
collegamento come un collegamento al nodo successivo in un elenco lineare e il car
collegamento come il valore del nodo corrente.
Detto questo, immagino che la prevalenza degli elenchi collegati nella programmazione funzionale sia collegata alla prevalenza della ricorsione sull'iterazione. Quando il tuo unico costrutto di loop a portata di mano è la (ricorsione) di coda, vuoi strutture di dati che siano facili da usare con quello; e le liste collegate sono perfette per questo.