Perché i linguaggi di programmazione funzionale richiedono la garbage collection?


14

Cosa impedisce a ghc di tradurre Haskell in un linguaggio di programmazione concatenativo come la logica combinatoria e quindi semplicemente usare l'allocazione dello stack per tutto? Secondo Wikipedia, la traduzione dal calcolo lambda alla logica combinatoria è banale, e inoltre, i linguaggi di programmazione concatenativa possono fare affidamento esclusivamente su uno stack per l'allocazione della memoria. È possibile fare questa traduzione ed eliminare così la raccolta dei rifiuti per lingue come Haskell e ocaml? Ci sono aspetti negativi nel fare questo?

EDIT: spostato qui /programming/39440412/why-do-functional-programming-languages-require-garbage-collection


Il linguaggio di programmazione Cat si presenta come un esempio di una funzione, linguaggio basato su stack.
Petr Pudlák,

1
Questa non è una domanda a livello di ricerca, in quanto la raccolta dei rifiuti è trattata in corsi di laurea sui linguaggi di programmazione (oltre che sulla necessità di farlo). Passare a cs.stackexchange.com
Andrej Bauer,

Errore mio. Conosci la risposta alla mia domanda?
Nicholas Grasevski,

5
Penso che ci sia una risposta a livello di ricerca da dare a questa domanda, mentre ricordo di averla affrontata anche durante i miei anni di laurea: tutto in una lingua come Haskell sembra un'applicazione funzionale, che vive nello stack. Penso che spiegare perché sono necessarie le chiusure, perché vivono nell'heap e forse quali "dati che sfuggono all'ambito della funzione" hanno a che fare con una risposta molto istruttiva (che non sono sicuro di essere qualificato a dare, Sfortunatamente).
cody

2
λ

Risposte:


16

Tutti i seguenti commenti si basano sulla scelta di una strategia di implementazione standard che utilizza le chiusure per rappresentare i valori delle funzioni e un ordine di valutazione call-by-value:

  1. Per il calcolo lambda puro, la raccolta dei rifiuti non è necessaria. Questo perché non è possibile formare cicli nell'heap: ogni nuovo valore allocato può contenere solo riferimenti a valori precedentemente allocati, e quindi il grafico della memoria forma un DAG - quindi il conteggio dei riferimenti è sufficiente per gestire la memoria.

  2. La maggior parte delle implementazioni non utilizza il conteggio dei riferimenti per due motivi.

    1. Supportano una forma di tipo di puntatore (ad esempio, il refcostruttore del tipo in ML), e quindi possono essere formati veri cicli nell'heap.
    2. Da allora, il conteggio dei riferimenti è molto meno efficiente della raccolta dei rifiuti
      • richiede molto spazio aggiuntivo per mantenere i conteggi dei riferimenti e
      • aggiornare i conteggi è di solito lavoro sprecato, e
      • gli aggiornamenti dei conteggi creano un sacco di contese di scrittura che uccidono le prestazioni parallele.
  3. Le lingue tipizzate in modo lineare possono eliminare il conteggio dei riferimenti (essenzialmente perché i conteggi sono 0-1: o il valore ha un singolo riferimento o è morto e può essere liberato).

  4. Tuttavia, l'allocazione dello stack non è ancora sufficiente. Questo perché è possibile formare valori di funzione che si riferiscono a variabili libere (cioè, dobbiamo implementare chiusure di funzioni), se si allocano cose nello stack, allora i valori attivi possono essere interfogliati con valori morti, e questo causerà un errore asintotico utilizzo dello spazio.

  5. Puoi ottenere gli asintotici giusti sostituendo uno stack con uno "stack di spaghetti" (ovvero, implementa lo stack come elenco collegato nell'heap, in modo da poter ritagliare i frame morti secondo necessità).

  6. Se si desidera una vera disciplina dello stack, è possibile utilizzare i sistemi di tipi basati sulla "logica ordinata" (essenzialmente tipi lineari meno scambio).


2
Non è forse la ragione di base per (2) che - anche senza effetti collaterali osservabili - le implementazioni vogliono avere un operatore efficiente per la ricorsione (reciproca), ovvero quella che forma effettivamente un ciclo nell'heap?
Andreas Rossberg,

@andreasrossberg: ho pensato di menzionarlo, ma l'ho lasciato fuori dal momento che puoi usare il combinatore y per la ricorsione.
Neel Krishnaswami,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.