5

Ho una domanda di carattere generale su interpreti di linguaggi funzionali:Vuol runtime usano generalmente un'interpretazione imperativo-come codice di linguaggio funzionale

In realtà ci sono eventuali vantaggi di utilizzare un linguaggio funzionale rispetto a un linguaggio imperativo in fase di esecuzione (o che farsi strada verso l'interprete)?

Nessuna delle domande che ho visto (come ad esempio this) arriva a questa domanda e le ricerche sono inondate di argomenti sulle definizioni di lingue diverse.

MODIFICA: messo a nudo l'unica domanda che ho finito per aver bisogno di una risposta.

+2

Cosa intendi per vantaggi che si fanno strada all'interprete? – sepp2k

+1

@ sepp2k Proprio come gli esempi specifici che ho elencato: sembrano esserci varie caratteristiche comuni dei linguaggi di programmazione funzionale. Voglio sapere se queste caratteristiche che sembrano differenziare la programmazione funzionale dallo stile imperativo in realtà fanno alcuna differenza in fase di esecuzione, o è solo una differenza più superficiale nello stile di codifica che differenzia i due. Ha senso? –

+0

Ho cambiato il titolo e un po 'la domanda, spero che ora sia più chiaro. –

risposta

29

La risposta breve è: tutto viene compilato in un linguaggio di basso livello alla fine (linguaggio assembly o macchina virtuale). Le lingue funzionali e imperative sono sullo stesso piano: devono compilare i loro meccanismi di astrazione per adattarsi a ciò che è disponibile sulla macchina.
Dove la lingua fa la differenza è quanto corrispondano strettamente al codice di basso livello sottostante (fornendo funzionalità di basso livello per ottimizzare il codice a mano quando è preferibile) e quali ottimizzazioni consentono o rendono più semplice avendo una semantica pulita che fornisce forti motivazioni di ragionamento . Ad esempio, quando si compila in codice nativo, la ricorsione non è (in generale) compilata in loop, ma in salti alle etichette, proprio come i loop: la maggior parte dei linguaggi assembly non ha né loop né ricorsione. Ovviamente, se si compila su una macchina virtuale con loop ma senza salti, è necessario produrre loop; questo è un problema, ad esempio, sulla Java Virtual Machine, perché le chiamate tail generiche sono più espressive dei loop e si deve aggirare questa limitazione, rinunciando ad una certa efficienza.

I "vantaggi" dei programmi funzionali possono essere che, poiché la semantica si comporta meglio, è possibile ragionare più facilmente sul programma e, ad esempio, esprimere le ottimizzazioni in un modo più semplice. Molti compilatori utilizzano al giorno d'oggi il modulo intermedio Single Static Assignment (SSA), che è fondamentalmente un linguaggio funzionale di basso livello¹, sebbene sia stato scoperto indipendentemente dalle persone della comunità del compilatore. La maggior parte delle ottimizzazioni è più facile da fare quando, ad esempio, sono state eliminate le mutazioni variabili e una variabile mantiene lo stesso valore in tutto il suo ambito. Esistono alcune tecniche per eseguire l'allocazione dei registri in more efficient ways su tali moduli intermedi funzionali.

¹: vedere il breve articolo di Andrew Appel del 1998: SSA is Functional Programming; se sei interessato a dettagli sul modulo SSA, ecco lo some reading notes sulla relazione tra SSA e altre forme intermedie funzionali, come ad esempio CPS.

È inoltre possibile ottenere vantaggi di ottimizzazione dalla purezza (assenza di effetti collaterali, o almeno un buon controllo su cui il calcolo sarà privo di effetti collaterali) e tipizzazione statica. Dalla purezza puoi ottenere potenti ottimizzazioni come o fusion (eliminando le strutture di dati intermedi), e dalla digitazione puoi ottenere forti garanzie sulla forma dei tuoi valori (ecco perché alcuni linguaggi dinamici cercano di consentire alcune forme di annotazioni di tipo limitato per l'ottimizzazione scopi) che consentono di generare codice migliore.

Per quanto riguarda l'accesso alle funzioni di basso livello: Fortran, C e C++ sono probabilmente le lingue migliori e più ampiamente disponibili "possono andare molto di basso livello".Alcune lingue cercano di fornire alcune di queste funzionalità: ad esempio ATS (originariamente un linguaggio di programmazione funzionale, sebbene sia così semplice da vedere) offre un buon controllo sull'allocazione dell'heap della versione di allocazione dello stack, sia Haskell che the CLR (C#,etc.) fornire unboxed tipi compositi come casi speciali di ragionamento di basso livello e allo stesso modo sta cercando di fornire modi per prendere decisioni a basso livello sul consumo di memoria.
Tuttavia, mentre questo è sicuramente utile quando hai isolato una piccola sezione di codice che è fondamentale per le tue prestazioni, e vuoi ottimizzarne l'inferno (rinunciare ad alcune flessibilità/semplicità/manutenibilità), questo non cambierà la tua vita nelle situazioni quotidiane, a meno che tu non sia un programmatore embedded/kernel. Probabilmente otterrai un miglioramento delle prestazioni complessivo da un linguaggio produttivo che ti consentirà di utilizzare il giusto livello di astrazione e dedicare più tempo alla scelta del design e degli algoritmi corretti per il tuo problema. Certo, si potrebbe desiderare di avere entrambi, ed è possibile ma difficile.

+0

Questo è perfetto, grazie. –

0

Esistono effettivamente vantaggi nell'utilizzo di un linguaggio funzionale rispetto a un linguaggio imperativo in fase di esecuzione (o che si dirigono verso l'interprete)?

Sì. Se si utilizza un linguaggio funzionale, il vantaggio è che lo scrittore dell'interprete è probabilmente fatto più velocemente. Se si utilizza un imperativo, è possibile utilizzare un po 'meno di memoria e CPU.

Quindi, indipendentemente da come lo si fa, ci sono dei vantaggi.

Ma, dati due interpreti, uno scritto in una lingua imperativa e l'altro in una funzionale, e dato che entrambi sono corretti, non si poteva capire dai risultati di un programma che era stato usato l'interprete.

Problemi correlati