Il più chiaro esempio di condivisione nella programmazione funzionale viene da Clean, che si basa sul grafico riscrittura.Lì, un calcolo si riferisce a un DAG, in modo da poter vedere l'espressione (sin x) * (sin x)
come
(*)
/ \
sin x sin x
sistemi di riscrittura di grafi hanno un concetto esplicito di condivisione, in modo da poter esprimere che il calcolo come
(*)
/\
\/
sin x
puntando il nodo di moltiplicazione allo stesso nodo, condividendo così il calcolo di sin x
. I sistemi di riscrittura a termine non hanno una nozione così esplicita di condivisione, ma l'ottimizzazione è ancora rilevante. In GHC, a volte è possibile esprimere la condivisione con variabili locali, ad es. riscrittura
f x = (sin x) * (sin x)
in
f x = sinx * sinx
where sinx = sin x
Ma poiché i due sono semanticamente equivalenti, il compilatore è libero di attuare sia allo stesso modo, con o senza condivisione. Secondo la mia comprensione, il GHC generalmente preserverà la condivisione introdotta con variabili locali e talvolta la introdurrà (aggiungendo la condivisione al primo), ma senza alcuna espressione formale di condivisione nei sistemi di riscrittura a termine, il comportamento dipende dall'implementazione (vedi commento e risposta del tel).
Condivisione di tocchi I/O perché i valori di effetti collaterali non possono essere condivisi. Se consideriamo un linguaggio impura, v'è una differenza tra
(string-append (read-line)
(read-line))
e
(let ((s (read-line)))
(string-append s s))
Il primo esegue l'azione IO due volte, chiedendo due linee da parte degli utenti e li aggiungendo; il secondo "condivide" l'azione IO, eseguendola una volta e aggiungendola a se stessa. In generale, la condivisione di un calcolo puro riduce il tempo di esecuzione senza modificare il risultato del programma, mentre la condivisione di un valore di effetto collaterale (che può cambiare nel tempo o interagire con l'utente) modifica il risultato. Affinché il compilatore possa condividere automaticamente i calcoli, deve sapere che sono puri e che quindi la riduzione del numero di valutazioni non ha importanza. Pulito lo fa con i tipi di unicità; un'azione IO ha l'attributo type UNQ, che dice al compilatore che non deve essere condiviso. Haskell fa lo stesso in modo diverso con la monade IO.
La memorizzazione nella cache dei dati per il riutilizzo è piuttosto detta "memoizzazione", non "condivisione". Se si dispone di dati a forma di albero che contengono la stessa sottostruttura più volte, trasformarli in un grafico aciclico diretto (DAG) per "condividere" la sottostruttura comune; questo è ciò che chiamerei condivisione. Inoltre, la domanda (a causa della sua natura aperta) non si adatta perfettamente al formato di SO. Potresti renderlo più concreto, dare esempi, ... – chris