Programmazione funzionale, dichiarativa e imperativa [chiuso]


466

Cosa significano i termini programmazione funzionale, dichiarativa e imperativa?


3
Ci sono alcune grandi risposte qui. Una cosa interessante non completamente chiarita è che il dichiarativo e l' imperativo sono complementari e simbiotici, più che semplici stili o cosa rispetto a come .
Kit

1
@Kit Imo, alcune delle risposte in questa pagina stanno combinando i termini. DP == trasparenza referenziale (RT). DP e IP sono opposti, quindi gli afaici non sono un complemento di un intero, cioè un intero programma può essere scritto in entrambi gli stili. La chiamata a una funzione può essere DP (RT) o IP, la sua implementazione potrebbe essere una o una combinazione. Non sono simbiotici nel senso che una chiamata a una funzione IP in una funzione DP altrimenti può rendere IP la chiamata della funzione DP. Sono simbiotici, nel senso che i programmi del mondo reale (ad es. Reattivo funzionale) possono impiegare un mix, ad es. Chiamate IP di alto livello in funzioni DP.
Shelby Moore III,

dovrebbe essere aggiunto al wiki o un link su qualcosa di simile al wiki ecc. ecco un ottimo link in wikipedia en.wikipedia.org/wiki/Comparison_of_programming_paradigms
Joe


1
Questa domanda è in discussione su Meta: meta.stackoverflow.com/q/342784/2751851
duplode

Risposte:


262

Al momento della stesura di questo, le risposte più votate in questa pagina sono imprecise e confuse sulla definizione dichiarativa vs. imperativa, inclusa la risposta che cita Wikipedia. Alcune risposte stanno combinando i termini in diversi modi.

Fai riferimento anche alla mia spiegazione del perché la programmazione del foglio di calcolo è dichiarativa, indipendentemente dal fatto che le formule mutino le celle.

Inoltre, diverse risposte affermano che la programmazione funzionale deve essere un sottoinsieme di dichiarativi. Da quel punto dipende se differenziamo la "funzione" dalla "procedura". Consente di gestire prima l'imperativo e il dichiarativo.

Definizione di espressione dichiarativa

L' unico attributo che può eventualmente differenziare un'espressione dichiarativa da un'espressione imperativa è la trasparenza referenziale (RT) delle sue sottoespressioni. Tutti gli altri attributi sono condivisi tra entrambi i tipi di espressioni o derivati ​​dalla RT.

Un linguaggio dichiarativo al 100% (cioè uno in cui ogni espressione possibile è RT) non (tra gli altri requisiti di RT) non consente la mutazione dei valori memorizzati, ad esempio HTML e la maggior parte di Haskell.

Definizione di espressione RT

RT è spesso definito come "privo di effetti collaterali". Il termine effetti non ha una definizione precisa, quindi alcune persone non concordano sul fatto che "nessun effetto collaterale" è uguale a RT. RT ha una definizione precisa .

Poiché ogni sottoespressione è concettualmente una chiamata di funzione, RT richiede che l'implementazione di una funzione (ovvero le espressioni all'interno della funzione chiamata) non possa accedere allo stato mutabile esterno alla funzione (l'accesso allo stato locale mutabile è permesso). In parole povere, la funzione (implementazione) dovrebbe essere pura .

Definizione di pura funzione

Si dice spesso che una funzione pura non abbia "effetti collaterali". Il termine effetti non ha una definizione precisa, quindi alcune persone non sono d'accordo.

Le funzioni pure hanno i seguenti attributi.

  • l'unica uscita osservabile è il valore di ritorno.
  • l'unica dipendenza di output sono gli argomenti.
  • gli argomenti sono completamente determinati prima che venga generato qualsiasi output.

Ricorda che RT si applica alle espressioni (che include le chiamate di funzione) e la purezza si applica alle (implementazioni di) funzioni.

Un esempio oscuro di funzioni impure che creano espressioni RT è la concorrenza, ma ciò è dovuto al fatto che la purezza è interrotta a livello di astrazione di interruzione. Non hai davvero bisogno di saperlo. Per creare espressioni RT, chiamate funzioni pure.

Attributi derivati ​​di RT

Qualsiasi altro attributo citato per la programmazione dichiarativa, ad esempio la citazione del 1999 usata da Wikipedia, deriva da RT o è condiviso con la programmazione imperativa. Dimostrando così che la mia definizione precisa è corretta.

Nota, l'immutabilità di valori esterni è un sottoinsieme dei requisiti per RT.

  • I linguaggi dichiarativi non hanno strutture di controllo in loop, ad esempio fore while, poiché a causa dell'immutabilità , la condizione del loop non cambierebbe mai.

  • I linguaggi dichiarativi non esprimono un flusso di controllo diverso dall'ordine delle funzioni nidificate (ovvero dipendenze logiche), perché a causa dell'immutabilità , altre scelte dell'ordine di valutazione non cambiano il risultato (vedere sotto).

  • I linguaggi dichiarativi esprimono "passi" logici (cioè l'ordine di chiamata della funzione RT nidificato), ma se ogni chiamata di funzione è un semantico di livello superiore (ovvero "cosa fare") non è un requisito della programmazione dichiarativa. La distinzione dall'imperativo è che a causa dell'immutabilità (cioè più in generale RT), questi "passi" non possono dipendere dallo stato mutabile, piuttosto solo dall'ordine relazionale della logica espressa (cioè dall'ordine di annidamento delle chiamate di funzione, ovvero sottoespressioni ).

    Ad esempio, il paragrafo HTML <p>non può essere visualizzato fino a quando non sono state valutate le sottoespressioni (ovvero i tag) nel paragrafo. Non esiste uno stato mutabile, ma solo una dipendenza dell'ordine dovuta alla relazione logica della gerarchia di tag (annidamento di sottoespressioni, che sono chiamate di funzione annidate in modo analogo ).

  • Quindi esiste l'attributo derivato dell'immutabilità (più in generale RT), che le espressioni dichiarative, esprimono solo le relazioni logiche delle parti costituenti (cioè degli argomenti della funzione di sottoespressione) e non le relazioni di stato mutabili .

Ordine di valutazione

La scelta dell'ordine di valutazione delle sottoespressioni può dare un risultato variabile solo quando una qualsiasi delle chiamate di funzione non è RT (ovvero la funzione non è pura), ad esempio si accede a uno stato mutabile esterno a una funzione all'interno della funzione.

Ad esempio, in alcune espressioni nidificate, ad esempio f( g(a, b), h(c, d) ), la valutazione ansioso e pigro degli argomenti funzione emette gli stessi risultati se le funzioni f, ge hsono puri.

Considerando che, se le funzioni f, ge hnon sono pure, la scelta dell'ordine di valutazione può dare un risultato diverso.

Nota, le espressioni nidificate sono funzioni concettualmente nidificate, poiché gli operatori di espressioni sono solo chiamate di funzione mascherate da prefisso unario, postfisso unario o notazione infettiva binaria.

Tangenzialmente, se tutti gli identificatori, ad esempio a, b, c, d, sono immutabili ovunque, stato esterno per il programma non può essere letta (per esempio I / O), e non v'è nessuna rottura livello di astrazione, quindi funzioni sono sempre pura.

Tra l'altro, Haskell ha una sintassi diversa, f (g a b) (h c d).

Dettagli dell'ordine di valutazione

Una funzione è una transizione di stato (non un valore memorizzato mutabile) dall'ingresso all'uscita. Per le composizioni RT di chiamate a funzioni pure , l'ordine di esecuzione di queste transizioni di stato è indipendente. La transizione di stato di ciascuna chiamata di funzione è indipendente dalle altre, a causa della mancanza di effetti collaterali e del principio secondo cui una funzione RT può essere sostituita dal suo valore memorizzato nella cache . Per correggere un malinteso popolare , la pura composizione monadica è sempre dichiarativa e RT , nonostante il fatto che la IOmonade di Haskell sia discutibilmente impura e quindi imperativa contenga lo Worldstato esterno al programma (ma nel senso della precisazione sottostante, gli effetti collaterali sono isolati).

Valutazione desiderosa significa che gli argomenti delle funzioni vengono valutati prima che la funzione venga chiamata, e la valutazione pigra significa che gli argomenti non vengono valutati fino a quando (e se) si accede all'interno della funzione.

Definizione : i parametri della funzione sono dichiarati nel sito della definizione della funzione e gli argomenti della funzione sono forniti nel sito della chiamata della funzione . Conosci la differenza tra parametro e argomento .

Concettualmente, tutte le espressioni sono (una composizione di) chiamate di funzione, ad es. Le costanti sono funzioni senza input, gli operatori unari sono funzioni con un input, gli operatori di infissione binaria sono funzioni con due input, i costruttori sono funzioni e persino le istruzioni di controllo (ad es if. for, while) può essere modellato con funzioni. L' ordine che questi argomenti funzioni (da non confondere con ordine chiamata di funzione annidata) vengono valutati non è dichiarato dalla sintassi, ad esempio, f( g() )potrebbe avidamente valutare gpoi fsu g's risultato o potrebbe valutare fe solo pigramente valutare gse il suo risultato è necessaria all'interno f.

Un avvertimento, nessun linguaggio completo di Turing (cioè che consente la ricorsione illimitata) è perfettamente dichiarativo, ad esempio una valutazione pigra introduce memoria e indeterminismo temporale. Ma questi effetti collaterali dovuti alla scelta dell'ordine di valutazione sono limitati al consumo di memoria, al tempo di esecuzione, alla latenza, alla non terminazione e all'isteresi esterna, quindi alla sincronizzazione esterna.

Programmazione funzionale

Poiché la programmazione dichiarativa non può avere loop, l'unico modo per iterare è la ricorsione funzionale. È in questo senso che la programmazione funzionale è collegata alla programmazione dichiarativa.

Ma la programmazione funzionale non si limita alla programmazione dichiarativa . La composizione funzionale può essere contrastata con il sottotipo , in particolare per quanto riguarda il Problema di espressione , in cui l'estensione può essere ottenuta aggiungendo sottotipi o decomposizione funzionale . L'estensione può essere un mix di entrambe le metodologie.

La programmazione funzionale di solito rende la funzione un oggetto di prima classe, il che significa che il tipo di funzione può apparire nella grammatica ovunque qualsiasi altro tipo possa. Il risultato è che le funzioni possono inserire e operare su funzioni, fornendo così la separazione delle preoccupazioni enfatizzando la composizione delle funzioni, cioè separando le dipendenze tra le sottocomputer di un calcolo deterministico.

Ad esempio, invece di scrivere una funzione separata (e impiegare la ricorsione invece di loop se la funzione deve anche essere dichiarativa) per ciascuno di un numero infinito di possibili azioni specializzate che potrebbero essere applicate a ciascun elemento di una raccolta, la programmazione funzionale impiega iterazione riutilizzabile funzioni, ad esempio map, fold, filter. Queste funzioni di iterazione introducono una funzione di azione specializzata di prima classe. Queste funzioni di iterazione ripetono la raccolta e richiamano la funzione di azione specializzata input per ciascun elemento. Queste funzioni di azione sono più concise perché non devono più contenere le istruzioni di ciclo per iterare la raccolta.

Tuttavia, nota che se una funzione non è pura, allora è davvero una procedura. Possiamo forse sostenere che la programmazione funzionale che utilizza funzioni impure è in realtà una programmazione procedurale. Pertanto, se concordiamo che le espressioni dichiarative sono RT, allora possiamo dire che la programmazione procedurale non è programmazione dichiarativa, e quindi potremmo sostenere che la programmazione funzionale è sempre RT e deve essere un sottoinsieme della programmazione dichiarativa.

Parallelismo

Questa composizione funzionale con funzioni di prima classe può esprimere la profondità del parallelismo separando la funzione indipendente.

Principio di Brent: il calcolo con lavoro w e profondità d può essere implementato in una PRAM con processore p nel tempo O (max (w / p, d)).

Sia la concorrenza che il parallelismo richiedono anche una programmazione dichiarativa , ovvero immutabilità e RT.

Quindi da dove nasce questa pericolosa ipotesi che il parallelismo == concorrenza? È una conseguenza naturale delle lingue con effetti collaterali: quando la tua lingua ha effetti collaterali ovunque, allora ogni volta che provi a fare più di una cosa alla volta hai essenzialmente un non determinismo causato dall'interlacciamento degli effetti di ogni operazione . Quindi, nei linguaggi con effetti collaterali, l'unico modo per ottenere il parallelismo è la concorrenza; non è quindi sorprendente che spesso vediamo i due confusi.

Ordine di valutazione FP

Si noti che l'ordine di valutazione influisce anche sulla terminazione e sugli effetti collaterali delle prestazioni della composizione funzionale.

Eager (CBV) e lazy (CBN) sono duelli categorici [ 10 ], perché hanno un ordine di valutazione invertito, cioè se le funzioni esterne o interne rispettivamente vengono valutate per prime. Immagina un albero capovolto, quindi desideroso valuta dalle punte del ramo dell'albero delle funzioni fino alla gerarchia dei rami fino al tronco delle funzioni di livello superiore; mentre pigro valuta dal tronco fino alle punte del ramo. Eager non ha prodotti congiuntivi ("e", a / k / a "prodotti" categorici) e pigro non ha coprodotti disgiuntivi ("o", a / k / a "somme" categoriche) [ 11 ].

Prestazione

  • desideroso

    Come per la non terminazione, l'entusiasmo è troppo impaziente di una composizione funzionale congiuntiva, cioè la struttura di controllo compositiva fa un lavoro inutile che non viene fatto con pigro. Ad esempio , desideroso e inutilmente mappa l'intera lista su booleani, quando è composta da una piega che termina sul primo vero elemento.

    Questo lavoro non necessario è la causa del preteso "fino a" un ulteriore log n fattore nella complessità temporale sequenziale di desideroso contro pigro, entrambi con funzioni pure. Una soluzione consiste nell'utilizzare i funzione (ad es. Elenchi) con costruttori pigri (ovvero desiderosi di prodotti pigri opzionali), poiché con l'entusiasmo l'erroneità dell'erroneità deriva dalla funzione interna. Questo perché i prodotti sono tipi costruttivi, ovvero tipi induttivi con un'algebra iniziale su un punto di fissaggio iniziale [ 11 ]

  • Pigro

    Come per la non terminazione, il pigro è troppo pigro con una composizione funzionale disgiuntiva, vale a dire che la finalità coinduttiva può avvenire più tardi del necessario, risultando in un lavoro non necessario e nel non determinismo del ritardo che non è il caso di desideroso [ 10 ] [ 11 ] . Esempi di finalità sono le eccezioni di stato, temporizzazione, non terminazione ed esecuzione. Questi sono effetti collaterali imperativi, ma anche in un linguaggio dichiarativo puro (ad es. Haskell), c'è uno stato nell'imperativo IO monade (nota: non tutte le monadi sono imperative!) Implicito nell'allocazione dello spazio, e il tempismo è stato relativo all'imperativo mondo reale. L'uso di pigro anche con coprodotti desiderosi opzionali perde "pigrizia" nei coprodotti interni, perché con pigro la pigrizia errata ha origine dalla funzione esterna(vedere l'esempio nella sezione Non-termination, dove == è una funzione dell'operatore binario esterno). Questo perché i coprodotti sono limitati dalla finalità, cioè tipi coinduttivi con un'algebra finale su un oggetto finale [ 11 ].

    Lazy causa indeterminismo nella progettazione e nel debug di funzioni per latenza e spazio, il cui debug è probabilmente al di là delle capacità della maggior parte dei programmatori, a causa della dissonanza tra la gerarchia di funzioni dichiarata e l'ordine di valutazione del runtime. Le funzioni pure pigre, valutate con entusiasmo, potrebbero potenzialmente introdurre una non terminazione mai vista prima durante l'esecuzione. Al contrario, le funzioni pure desiderose valutate con lazy, potrebbero potenzialmente introdurre indeterminismo di spazio e latenza mai visto prima durante l'esecuzione.

Non-terminazione

In fase di compilazione, a causa del problema di Halting e della ricorsione reciproca in un linguaggio completo di Turing, non è possibile garantire in genere che le funzioni vengano interrotte.

  • desideroso

    Con desideroso ma non pigro, per la congiunzione di Head"e" Tail, se uno dei due Heado Tailnon termina, rispettivamente rispettivamente List( Head(), Tail() ).tail == Tail()o List( Head(), Tail() ).head == Head()non è vero perché il lato sinistro non lo fa e il lato destro termina.

    Considerando che con pigro terminano entrambe le parti. Così desideroso è troppo desideroso di prodotti congiuntivi e non termina (comprese le eccezioni di runtime) nei casi in cui non è necessario.

  • Pigro

    Con pigro ma non desideroso, per la disgiunzione di 1"o" 2, se fnon termina, allora List( f ? 1 : 2, 3 ).tail == (f ? List( 1, 3 ) : List( 2, 3 )).tailnon è vero perché termina il lato sinistro e il lato destro no.

    Considerando che, con impaziente nessuna delle due parti termina, il test di uguaglianza non viene mai raggiunto. Quindi pigro è troppo pigro con coprodotti disgiuntivi, e in quei casi non riesce a terminare (comprese le eccezioni di runtime) dopo aver fatto più lavoro di quanto desiderasse.

[ 10 ] Continuazioni dichiarative e dualità categorica, Filinski, sezioni 2.5.4 Un confronto tra CBV e CBN e 3.6.1 CBV e CBN nella SCL.

[ 11 ] Continuazioni dichiarative e dualità categorica, Filinski, sezioni 2.2.1 Prodotti e coprodotti, 2.2.2 Oggetti terminali e iniziali, 2.5.2 CBV con prodotti pigri e 2.5.3 CBN con coprodotti desiderosi.


Anche con la programmazione dichiarativa dei vincoli, i vincoli non mutano mentre il risolutore trova la soluzione. Questo è ovvio perché non c'è modo di specificare un orario in cui cambiare. Anche i vincoli specificati rispetto ad altri vincoli vengono dichiarati tutti prima dell'esecuzione del solutore per trovare la soluzione. Questo è analogo alle formule dichiarative nel foglio di calcolo .
Shelby Moore III,

3
Abbreviazione non significa fornire una definizione. Dove ho scritto "RT è spesso abbreviato" senza effetti collaterali ", ciò non significa che la definizione di RT sia" nessun effetto collaterale ", perché le persone possono avere definizioni diverse per" effetti ". Se invece dicessi "RT è spesso abbreviato 'xyz'", un simbolo insignificante non dà alcuna definizione a RT. RT ha una definizione precisa che non cambia mai, indipendentemente dal simbolo che si utilizza per fare riferimento ad essa.
Shelby Moore III,

Non riesco a trovare un contro-esempio per la mia affermazione che ogni tipo di DP è RT. Ad esempio, il significato (ovvero il valore) dei termini di una grammatica sensibile al contesto non cambia in un momento o in una posizione diversi all'interno della grammatica. Vedi il mio commento sulla programmazione dei vincoli sopra.
Shelby Moore III,

1
L'equazione di C in stile ESP con RT in monade di stato non è valida , poiché ogni istruzione C può mutare lo stato globale, mentre "all'interno" della monade di stato ogni istruzione corrispondente genera una COPIA dello stato (così modificata). Il secondo è RT, il primo no. La composizione monadica è sempre RT. DP == RT è l'unico significato per DP che è un insieme disgiunto di attributi (la dimostrazione matematica sono corretta, altrimenti DP non ha senso).
Shelby Moore III,

1
Vorrei poter capire in passato la prima frase. Stavo leggendo il manuale di DAX che indicava che si trattava di un "linguaggio funzionale". Cosa significa questo? Non so andare a chiedere al tuo pop.
Nick.McDermaid

103

Non esiste una definizione oggettiva non ambigua per questi. Ecco come io li definirei:

Imperativo - Il focus è su ciò che passi il computer dovrebbe prendere piuttosto che ciò che il computer fare (ex C, C ++, Java.).

Dichiarativo - L'attenzione si concentra su ciò che il computer dovrebbe fare piuttosto che su come dovrebbe farlo (es. SQL).

Funzionale - un sottoinsieme di linguaggi dichiarativi che si concentra fortemente sulla ricorsione


1
Tieni a mente un paio di cose: 1) la spiegazione deve essere semplice anziché all-inclusive 2) come ho detto, ci sono diversi modi per definire queste lingue. Pertanto, la risposta potrebbe benissimo essere sbagliata per te e giusta per qualcun altro.
Jason Baker,

3
La programmazione funzionale non è "un sottoinsieme di linguaggi dichiarativi". La programmazione dichiarativa richiede l'immutabilità dei valori memorizzati, la programmazione funzionale no, se non è FP puro . Vedere la mia risposta . Vedi anche la spiegazione per le celle del foglio di calcolo . Le definizioni oggettive corrette non sono "ambigue". La programmazione imperativa si concentra anche "su ciò che il computer dovrebbe fare". L' unica distinzione è che la programmazione imperativa ha a che fare con valori memorizzati mutabili.
Shelby Moore III,

5
@ShelbyMooreIII - Tendo a concordare con Eric Meijer su questo. Non esiste davvero un "linguaggio funzionale non puro". Per quanto mi riguarda, Ocaml, F # e simili sono linguaggi imperativi con strutture di dati funzionali. Ma come ho detto nella mia risposta, non credo che ci sia una risposta obiettiva e non ambigua a questa domanda. Esistono diversi modi per definire le cose.
Jason Baker,

3
Si può dimostrare matematicamente che sta combinando termini, quando nessuna delle definizioni è inequivocabile, perché gli attributi scelti non sono un insieme disgiunto. Se si definisce FP come solo FP puro (cioè RT), allora non è distinto da DP, cfr. la mia risposta . Gli attributi disgiunti di FP includono il tipo di funzione di prima classe, che può essere una funzione imperativa. Ho trovato termini più ambigui qui e qui . Preferire il FP puro è ortogonale alla definizione di FP solo.
Shelby Moore III,

21
@ShelbyMooreIII - Stavo assumendo che l'OP volesse la sua risposta in inglese, non Math Nerd-ese. Se quello era un presupposto invalido, allora mi scuso.
Jason Baker,

54

imperativo e dichiarativo descrivono due stili opposti di programmazione. l'imperativo è l'approccio tradizionale "ricetta passo per passo" mentre il dichiarativo è più "questo è quello che voglio, ora capisci come farlo".

questi due approcci si verificano durante la programmazione, anche con lo stesso linguaggio e lo stesso programma. generalmente l'approccio dichiarativo è considerato preferibile, perché libera il programmatore dal dover specificare così tanti dettagli, pur avendo meno possibilità di bug (se descrivi il risultato che desideri, e alcuni processi automatici ben collaudati possono tornare indietro da quello a definire i passaggi, quindi si potrebbe sperare che le cose siano più affidabili rispetto alla necessità di specificare ogni passaggio manualmente).

d'altra parte, un approccio imperativo ti dà un controllo di livello più basso: è l '"approccio micromanager" alla programmazione. e ciò può consentire al programmatore di sfruttare la conoscenza del problema per fornire una risposta più efficiente. quindi non è insolito che alcune parti di un programma siano scritte in uno stile più dichiarativo, ma che le parti critiche per la velocità siano più imperative.

come puoi immaginare, la lingua che usi per scrivere un programma influenza quanto puoi essere dichiarativo - una lingua che ha "intelligenze" incorporate per capire cosa fare data una descrizione del risultato consentirà una dichiarazione molto più dichiarativa approccio rispetto a quello in cui il programmatore deve prima aggiungere quel tipo di intelligenza con codice imperativo prima di poter costruire un livello più dichiarativo in cima. quindi, ad esempio, un linguaggio come prolog è considerato molto dichiarativo perché ha un processo incorporato che cerca le risposte.

finora, noterai che non ho menzionato la programmazione funzionale . questo perché è un termine il cui significato non è immediatamente correlato agli altri due. nella sua programmazione più semplice e funzionale significa che usi le funzioni. in particolare, che si utilizza un linguaggio che supporta le funzioni come "valori di prima classe" - ciò significa che non solo è possibile scrivere funzioni, ma è possibile scrivere funzioni che scrivono funzioni (che scrivono funzioni che ...) e passare funzioni a funzioni. in breve: le funzioni sono flessibili e comuni come cose come stringhe e numeri.

potrebbe sembrare strano, quindi, che funzionale, imperativo e dichiarativo siano spesso citati insieme. la ragione di ciò è una conseguenza dell'idea "estrema" dell'idea della programmazione funzionale. una funzione, nel suo senso più puro, è qualcosa di matematico - una specie di "scatola nera" che accetta alcuni input e fornisce sempre lo stesso output. e quel tipo di comportamento non richiede la memorizzazione di variabili variabili. quindi se si progetta un linguaggio di programmazione il cui scopo è quello di implementare un'idea di programmazione funzionale molto pura e influenzata matematicamente, si finisce per rifiutare, in gran parte, l'idea di valori che possono cambiare (in un certo senso limitato, dal punto di vista tecnico).

e se lo fai - se limiti il ​​modo in cui le variabili possono cambiare - allora quasi per caso finisci per forzare il programmatore a scrivere programmi che sono più dichiarativi, perché gran parte della programmazione imperativa sta descrivendo come cambiano le variabili e non puoi più Fai quello! così risulta che la programmazione funzionale - in particolare la programmazione in un linguaggio funzionale - tende a dare un codice più dichiarativo.

per riassumere, quindi:

  • imperativo e dichiarativo sono due stili opposti di programmazione (gli stessi nomi sono usati per linguaggi di programmazione che incoraggiano quegli stili)

  • la programmazione funzionale è uno stile di programmazione in cui le funzioni diventano molto importanti e, di conseguenza, la modifica dei valori diventa meno importante. la limitata capacità di specificare cambiamenti nei valori impone uno stile più dichiarativo.

così la "programmazione funzionale" è spesso descritta come "dichiarativa".


5
La migliore spiegazione finora. Sembra che Funzionale e OOP siano ortogonali a Imperativo e Dichiarativo.
Didier A.

Diresti che la programmazione logica è dichiarativa? O è esso stesso ortogonale?
Didier A.

51

In breve:

Un linguaggio imperativo specifica una serie di istruzioni che il computer esegue in sequenza (fare questo, quindi farlo).

Un linguaggio dichiarativo dichiara un insieme di regole su quali output dovrebbero derivare da quali input (es. Se hai A, allora il risultato è B). Un motore applicherà queste regole agli input e fornirà un output.

Un linguaggio funzionale dichiara un insieme di funzioni matematiche / logiche che definiscono il modo in cui l'input viene tradotto in output. per esempio. f (y) = y * y. è un tipo di linguaggio dichiarativo.


1
La programmazione funzionale non è "un tipo di linguaggio dichiarativo". La programmazione dichiarativa richiede l'immutabilità dei valori memorizzati, la programmazione funzionale impura no. Vedere la mia risposta . Vedi anche la spiegazione per le celle del foglio di calcolo . L' unico motivo per cui la logica imperativa (ovvero le istruzioni) viene eseguita in sequenza è che a causa della presenza di valori memorizzati mutabili, il risultato dipende dall'ordine di valutazione. Usando il tuo vocabolario, una "istruzione" può (e una "regola" non può) operare su valori mutabili.
Shelby Moore III

23

Imperativo: come raggiungere il nostro obiettivo

   Take the next customer from a list.
   If the customer lives in Spain, show their details.
   If there are more customers in the list, go to the beginning

Dichiarativo: cosa vogliamo ottenere

   Show customer details of every customer living in Spain

Stai descrivendo la programmazione funzionale rispetto a non-FP, non dichiarativa contro programmazione imperativa. La programmazione funzionale è ortogonale alla polarità tra programmazione imperativa e dichiarativa. La programmazione dichiarativa richiede l'immutabilità dei valori memorizzati, la programmazione funzionale impura no. Vedere la mia risposta .
Shelby Moore III,

22

Programmazione imperativa indica qualsiasi tipo di programmazione in cui il programma è strutturato in base alle istruzioni che descrivono come verranno eseguite le operazioni eseguite da un computer .

Programmazione dichiarativa indica qualsiasi stile di programmazione in cui il programma è una descrizione del problema o della soluzione, ma non specifica esplicitamente come verrà svolto il lavoro .

La programmazione funzionale sta programmando valutando le funzioni e le funzioni delle funzioni ... Poiché la programmazione funzionale (rigorosamente definita) significa programmare definendo funzioni matematiche libere di effetti collaterali, quindi è una forma di programmazione dichiarativa ma non è l'unico tipo di programmazione dichiarativa .

Programmazione logica (ad esempio in Prolog) è un'altra forma di programmazione dichiarativa. Implica il calcolo decidendo se un'affermazione logica è vera (o se può essere soddisfatta). Il programma è in genere una serie di fatti e regole, vale a dire una descrizione piuttosto che una serie di istruzioni.

La riscrittura dei termini (ad esempio CASL) è un'altra forma di programmazione dichiarativa. Implica la trasformazione simbolica di termini algebrici. È completamente distinto dalla programmazione logica e dalla programmazione funzionale.


La programmazione funzionale non è "una forma di programmazione dichiarativa". La programmazione dichiarativa richiede l'immutabilità dei valori memorizzati, la programmazione funzionale impura no. Vedere la mia risposta . Vedi anche la spiegazione per le celle del foglio di calcolo . Il termine "lavoro" in "descrivere come fare il lavoro" non è definito. L' unica ragione per cui la logica imperativa (alias "istruzioni") viene eseguita in sequenza è che a causa della presenza di valori memorizzati mutabili, il risultato dipende dall'ordine di valutazione.
Shelby Moore III,

2
Per favore, leggi come stavo parlando della pura programmazione funzionale . Questi paradigmi possono incrociarsi e non voglio impantanarmi confrontando i linguaggi ibridi. In teoria, almeno la programmazione funzionale riguarda le funzioni piuttosto che descrivere il modo in cui un computer eseguirà ogni calcolo, quindi sostengo che sia dichiarativo.
Dafydd Rees l'

Ho modificato la mia risposta e, nella sezione "Programmazione funzionale", ho aggiunto uno scenario in cui potremmo sostenere che FP è sempre puro e FP impuro è davvero "programmazione procedurale". Ci scusiamo per non aver incluso questa interpretazione in precedenza.
Shelby Moore III,

13

imperativo : le espressioni descrivono la sequenza di azioni da eseguire (associativa)

dichiarativo - le espressioni sono dichiarazioni che contribuiscono al comportamento del programma (associativo, commutativo, idempotente, monotonico)

funzionale : le espressioni hanno valore come unico effetto; la semantica supporta il ragionamento equazionale


1
Le espressioni dichiarative contribuiscono al comportamento previsto del programma, l'imperativo può contribuire a ciò che è intenzionale o involontario. Dichiarativo non deve essere commutativo e idempotente, se questa è semantica intenzionale. Mi piace la tua concisa essenza funzionale, quindi l'ho votata.
Shelby Moore III,

10

Da quando ho scritto la mia risposta precedente, ho formulato una nuova definizione della proprietà dichiarativa che è citata di seguito. Ho anche definito la programmazione imperativa come doppia proprietà.

Questa definizione è superiore a quella che ho fornito nella mia risposta precedente, perché è concisa ed è più generale. Ma può essere più difficile brontolare, perché le implicazioni dei teoremi di incompletezza applicabili alla programmazione e alla vita in generale sono difficili per gli esseri umani che si muovono intorno.

La spiegazione citata della definizione discute il ruolo della pura programmazione funzionale nella programmazione dichiarativa.

Tutti i tipi di programmazione esotici si adattano alla seguente tassonomia di dichiarativo contro imperativo, poiché la seguente definizione afferma che sono doppi.

Dichiarativo vs. Imperativo

La proprietà dichiarativa è strana, ottusa e difficile da catturare in una definizione tecnicamente precisa che rimane generale e non ambigua, perché è un'idea ingenua che possiamo dichiarare il significato (alias semantica) del programma senza incorrere in effetti collaterali non intenzionali. Esiste una tensione intrinseca tra espressione di significato ed evitamento di effetti indesiderati, e questa tensione deriva in realtà dai teoremi di incompletezza della programmazione e del nostro universo.

È una semplificazione eccessiva, tecnicamente imprecisa e spesso ambigua definire dichiarativo come " cosa fare " e imperativo come " come fare " . Un caso ambiguo è il " cosa " è il " come " in un programma che genera un programma, un compilatore.

Evidentemente la ricorsione illimitata che completa un linguaggio di Turing , è anche analoga nella semantica, non solo nella struttura sintattica della valutazione (nota anche come semantica operativa). Questo è logicamente un esempio analogo al teorema di Gödel: “ qualsiasi sistema completo di assiomi è anche incoerente ". Rifletti sulla stranezza contraddittoria di quella citazione! È anche un esempio che dimostra come l'espressione della semantica non abbia un limite dimostrabile, quindi non possiamo provare 2 che un programma (e analogamente la sua semantica) fermi, noto anche come teorema di Halting.

I teoremi di incompletezza derivano dalla natura fondamentale del nostro universo, che come affermato nella Seconda Legge della Termodinamica è " l'entropia (ovvero il numero di possibilità indipendenti) tende al massimo per sempre ". La codifica e la progettazione di un programma non è mai finita - è viva! - perché tenta di soddisfare un'esigenza del mondo reale e la semantica del mondo reale è in continua evoluzione e tende a più possibilità. Gli umani non smettono mai di scoprire cose nuove (inclusi errori nei programmi ;-).

Per catturare con precisione e tecnicamente questa nozione desiderata di cui sopra in questo strano universo che non ha margini (meditare che! Non esiste un "esterno" del nostro universo), richiede una definizione concisa ma ingannevolmente non semplice che suonerà errata fino a quando non viene spiegata profondamente.

Definizione:


La proprietà dichiarativa è dove esiste una sola serie di istruzioni che può esprimere ogni semantica modulare specifica.

La proprietà imperativa 3 è la doppia, in cui la semantica è incoerente sotto la composizione e / o può essere espressa con variazioni di insiemi di affermazioni.


Questa definizione di dichiarativo è distintamente locale nell'ambito semantico, nel senso che richiede che un semantico modulare mantenga il suo significato coerente indipendentemente da dove e come viene istanziato e impiegato nell'ambito globale . Quindi ogni semantico modulare dichiarativo dovrebbe essere intrinsecamente ortogonale a tutti gli altri possibili - e non un algoritmo o modello globale impossibile (a causa di teoremi di incompletezza) per testimoniare la coerenza, che è anche il punto di “ More Is Not Always Better " di Robert Harper, professore di Informatica alla Carnegie Mellon University, uno dei progettisti di Standard ML.

Esempi di queste semantiche dichiarative modulari includono i teorici di categoria, ad esempio iApplicative tipizzazione nominale, gli spazi dei nomi, i campi nominati e la scrittura a livello operativo della semantica, quindi la pura programmazione funzionale.

Quindi linguaggi dichiarativi ben progettati possono esprimere più chiaramente il significato , anche se con una certa perdita di generalità in ciò che può essere espresso, eppure un guadagno in ciò che può essere espresso con coerenza intrinseca.

Un esempio della suddetta definizione è l'insieme di formule nelle celle di un programma per fogli di calcolo, che non dovrebbero avere lo stesso significato quando vengono spostate in celle di colonne e righe diverse, vale a dire che gli identificatori di celle vengono modificati. Gli identificatori cellulari fanno parte e non superano il significato previsto. Quindi ogni risultato del foglio di calcolo è univoco rispetto agli identificatori di cella in una serie di formule. La semantica modulare coerente in questo caso è l'uso di identificatori di celle come input e output di funzioni pure per le formule di celle (vedi sotto).

Hyper Text Markup Language, noto anche come HTML, il linguaggio delle pagine Web statiche, è un esempio di un linguaggio dichiarativo altamente (ma non perfettamente 3 ) che (almeno prima di HTML 5) non era in grado di esprimere un comportamento dinamico. L'HTML è forse il linguaggio più semplice da imparare. Per un comportamento dinamico, un linguaggio di scripting imperativo come JavaScript era di solito combinato con HTML. L'HTML senza JavaScript si adatta alla definizione dichiarativa perché ogni tipo nominale (ovvero i tag) mantiene il suo significato coerente sotto la composizione all'interno delle regole della sintassi.

Una definizione concorrente per dichiarativo è la proprietà commutativa e idempotente delle dichiarazioni semantiche, cioè che le dichiarazioni possono essere riordinate e duplicate senza cambiarne il significato. Ad esempio, le istruzioni che assegnano valori ai campi con nome possono essere riordinate e duplicate senza modificare il significato del programma, se tali nomi sono modulari scritti in un ordine implicito. I nomi a volte implicano un ordine, ad esempio gli identificatori di cella includono la posizione di colonna e riga: lo spostamento di un totale sul foglio di calcolo ne modifica il significato. Altrimenti, queste proprietà implicitamente richiedono globalecoerenza della semantica. È generalmente impossibile progettare la semantica delle dichiarazioni in modo che rimangano coerenti se ordinate o duplicate in modo casuale, poiché l'ordine e la duplicazione sono intrinseci alla semantica. Ad esempio, le dichiarazioni "Foo esiste" (o costruzione) e "Foo non esiste" (e distruzione). Se si considera un'incoerenza casuale endemica della semantica prevista, si accetta questa definizione come abbastanza generale per la proprietà dichiarativa. In sostanza questa definizione è vacua come definizione generalizzata perché cerca di rendere la coerenza ortogonale alla semantica, cioè di sfidare il fatto che l'universo della semantica è dinamicamente illimitato e non può essere catturato in un paradigma di coerenza globale .

Richiedere le proprietà commutative e idempotenti per la (semantica di valutazione strutturale della) semantica operativa di livello inferiore converte la semantica operativa in una semantica modulare localizzata dichiarativa , ad esempio pura programmazione funzionale (inclusa la ricorsione invece di loop imperativi). Quindi l'ordine operativo dei dettagli di implementazione non influisce (cioè si diffonde a livello globale ) sulla coerenza della semantica di livello superiore. Ad esempio, l'ordine di valutazione (e teoricamente anche la duplicazione) delle formule del foglio di calcolo non ha importanza perché gli output non vengono copiati negli input fino a quando non sono stati calcolati tutti gli output, vale a dire analoghi alle funzioni pure.

C, Java, C ++, C #, PHP e JavaScript non sono particolarmente dichiarativi. La sintassi di Copute e la sintassi di Python sono accoppiate in modo più dichiarativo ai risultati previsti , ovvero semantica sintattica coerente che elimina l'estraneo in modo da poter comprendere facilmente il codice dopo averlo dimenticato. Copute e Haskell applicano il determinismo della semantica operativa e incoraggiano " non ripetere te stesso " (DRY), perché consentono solo il puro paradigma funzionale.


2 Anche dove possiamo dimostrare la semantica di un programma, ad esempio con la lingua Coq, questo è limitato alla semantica espressa nella digitazione e la digitazione non può mai catturare tutta la semantica di un programma, nemmeno per le lingue che sono non completo di Turing, ad es. con HTML + CSS è possibile esprimere combinazioni incoerenti che hanno quindi una semantica indefinita.

3 Molte spiegazioni affermano erroneamente che solo la programmazione imperativa ha istruzioni sintatticamente ordinate. Ho chiarito questa confusione tra programmazione imperativa e funzionale . Ad esempio, l'ordine delle istruzioni HTML non riduce la coerenza del loro significato.


Modifica: ho pubblicato il seguente commento sul blog di Robert Harper:

nella programmazione funzionale ... l'intervallo di variazione di una variabile è un tipo

A seconda di come si distingue la programmazione funzionale dalla programmazione imperativa, il proprio 'assegnabile' in un programma imperativo può anche avere un tipo che pone un limite alla sua variabilità.

L'unica definizione non confusa che attualmente apprezzo per la programmazione funzionale è a) funzioni come oggetti e tipi di prima classe, b) preferenza per la ricorsione su loop e / o c) funzioni pure - cioè quelle funzioni che non influiscono sulla semantica desiderata del programma quando memorizzato ( quindi una programmazione funzionale perfettamente pura non esiste in una semantica denotazionale per scopi generali a causa degli impatti della semantica operativa, ad es. allocazione della memoria ).

La proprietà idempotente di una funzione pura significa che la chiamata di funzione sulle sue variabili può essere sostituita dal suo valore, il che non è generalmente il caso degli argomenti di una procedura imperativa. Le funzioni pure sembrano essere dichiarative rispetto alle transizioni di stato non poste tra i tipi di input e di risultato.

Ma la composizione di funzioni pure non mantiene tale coerenza, poiché è possibile modellare un processo imperativo di effetti collaterali (stato globale) in un linguaggio di programmazione funzionale puro, ad esempio IOMonad di Haskell e inoltre è del tutto impossibile impedire di farlo in qualsiasi linguaggio di programmazione funzionale puro completo di Turing.

Come ho scritto nel 2012, che sembra al consenso simile dei commenti nel tuo recente blog , che la programmazione dichiarativa è un tentativo di catturare l'idea che la semantica prevista non è mai opaca. Esempi di semantica opaca sono la dipendenza dall'ordine, la dipendenza dalla cancellazione della semantica di livello superiore a livello di semantica operativa (ad es. I cast non sono conversioni e la generica reificata limita la semantica di livello superiore ) e la dipendenza da valori variabili che non possono essere verificati (dimostrato corretto) dal linguaggio di programmazione.

Pertanto, ho concluso che solo le lingue complete non turing possono essere dichiarative.

Pertanto, un attributo non ambiguo e distinto di un linguaggio dichiarativo potrebbe essere che la sua produzione può essere dimostrata obbedire a un insieme numeroso di regole generative. Ad esempio, per qualsiasi programma HTML specifico (ignorando le differenze nel modo in cui gli interpreti divergono) che non è scritto (ovvero non è Turing completo), la sua variabilità di output può essere enumerabile. O più succintamente un programma HTML è una pura funzione della sua variabilità. Idem un programma per fogli di calcolo è una pura funzione delle sue variabili di input.

Quindi mi sembra che le lingue dichiarative siano l'antitesi della ricorsione illimitata , cioè secondo il secondo teorema di incompletezza di Gödel i teoremi autoreferenziali non possono essere provati.

Lesie Lamport ha scritto una fiaba su come Euclide avrebbe potuto aggirare i teoremi di incompletezza di Gödel applicati alle prove matematiche nel contesto del linguaggio di programmazione mediante la congruenza tra tipi e logica (corrispondenza Curry-Howard, ecc.).


Robert Harper sembra concordare con me sull'insensatezza della maggior parte delle definizioni di dichiarativo , eppure non credo che abbia visto il mio sopra. Si avvicina alla mia definizione dove discute della semantica denotazionale, ma non arriva alla mia definizione. Il modello (semantica denotazionale) è di livello superiore .
Shelby Moore III,

7

Programmazione imperativa: dire alla "macchina" come fare qualcosa e, di conseguenza, accadrà quello che vuoi che accada.

Programmazione dichiarativa: dire alla "macchina" cosa vorresti succedere e lasciare che il computer capisse come farlo.

Esempio di imperativo

function makeWidget(options) {
    const element = document.createElement('div');
    element.style.backgroundColor = options.bgColor;
    element.style.width = options.width;
    element.style.height = options.height;
    element.textContent = options.txt;

    return element;
}

Esempio di dichiarativo

function makeWidget(type, txt) {
    return new Element(type, txt);
}

Nota: la differenza non è di brevità, complessità o astrazione. Come detto, la differenza è come vs cosa .


2
buono ma meglio se fornisci almeno un esempio per entrambi!
Pardeep Jain,

4

Oggi, nuovo focus: abbiamo bisogno delle classificazioni precedenti?

Gli aspetti Imperativo / Dichiarativo / Funzionale erano buoni in passato per classificare i linguaggi generici, ma oggigiorno tutti i "grandi linguaggi" (come Java, Python, Javascript, ecc.) Hanno qualche opzione (tipicamente framework ) da esprimere con "altro focus" rispetto al suo principale (solito imperativo) e per esprimere processi paralleli, funzioni dichiarative, lambda, ecc.

Quindi una buona variante di questa domanda è "Quale aspetto è buono classificare i framework oggi?" ... Un aspetto importante è qualcosa che possiamo etichettare "stile di programmazione" ...

Concentrati sulla fusione dei dati con l'algoritmo

Un buon esempio da spiegare. Come puoi leggere su jQuery su Wikipedia ,

L'insieme delle funzionalità principali di jQuery - selezione, spostamento e manipolazione di elementi DOM -, abilitato dal suo motore di selezione (...), ha creato un nuovo "stile di programmazione", fondendo algoritmi e strutture di dati DOM

Quindi jQuery è il miglior esempio (popolare) di concentrarsi su un "nuovo stile di programmazione" , che non è solo l'orientamento agli oggetti, è " Fondere algoritmi e strutture di dati ". jQuery è in qualche modo reattivo come fogli di calcolo, ma non "orientato alle celle", è " orientato al nodo DOM " ... Confrontando gli stili principali in questo contesto:

  1. Nessuna fusione : in tutti i "grandi linguaggi", in qualsiasi espressione Funzionale / Dichiarativa / Imperativa, il solito è "nessuna fusione" di dati e algoritmo, tranne che per qualche orientamento all'oggetto, che è una fusione nel punto di vista della struttura algebrica rigorosa .

  2. Un po 'di fusione : tutte le classiche strategie di fusione, al giorno d'oggi hanno un po' di framework che lo utilizza come paradigma ... flusso di dati , programmazione basata su eventi (o vecchi linguaggi specifici di dominio come awk e XSLT ) ... Come la programmazione con i moderni fogli di calcolo, sono anche esempi di stile di programmazione reattiva .

  3. Grande fusione : è "lo stile jQuery" ... jQuery è un linguaggio specifico di dominio incentrato su " fusione di algoritmi e strutture di dati DOM ".
    PS: altri "linguaggi di query", come XQuery, SQL (con PL come opzione di espressione imperativa) sono anche esempi di fusione di algoritmi di dati, ma sono isole , senza fusione con altri moduli di sistema ... Primavera , quando si usa find()-variants e clausole di specifica , è un altro buon esempio di fusione.


3

La programmazione dichiarativa sta programmando esprimendo una logica senza tempo tra l'input e l'output, ad esempio in pseudocodice, il seguente esempio sarebbe dichiarativo:

def factorial(n):
  if n < 2:
    return 1
  else:
    return factorial(n-1)

output = factorial(argvec[0])

Qui definiamo semplicemente una relazione chiamata "fattoriale" e definiamo la relazione tra l'output e l'input come quella relazione. Come dovrebbe essere evidente qui, qualsiasi linguaggio strutturato consente in qualche modo la programmazione dichiarativa. Un'idea centrale della programmazione dichiarativa sono i dati immutabili, se si assegna a una variabile, lo si fa solo una volta e poi mai più. Altre definizioni più rigorose implicano che potrebbero non esserci effetti collaterali, queste lingue sono talvolta chiamate "puramente dichiarative".

Lo stesso risultato in uno stile imperativo sarebbe:

a = 1
b = argvec[0]
while(b < 2):
  a * b--

output = a

In questo esempio, non abbiamo espresso alcuna relazione logica statica senza tempo tra l'input e l'output, abbiamo cambiato manualmente gli indirizzi di memoria fino a quando uno di loro ha ottenuto il risultato desiderato. Dovrebbe essere evidente che tutte le lingue permettono alla semantica dichiarativa di estendersi, ma non tutte consentono imperativo, alcune lingue dichiarative "puramente" consentono del tutto effetti collaterali e mutazione.

Si dice spesso che le lingue dichiarative specificano "cosa deve essere fatto", al contrario di "come farlo", penso che sia un termine improprio, i programmi dichiarativi specificano ancora come si debba ottenere da input a output, ma in un altro modo, il la relazione che specifichi deve essere effettivamente calcolabile (termine importante, cercalo se non lo conosci). Un altro approccio è la programmazione non deterministica , che specifica in realtà solo quali condizioni soddisfano un risultato, prima che l'implementazione finisca per esaurire tutti i percorsi in prova ed errore fino a quando non ha successo.

Le lingue puramente dichiarative includono Haskell e Pure Prolog. Una scala mobile dall'una all'altra sarebbe: Pure Prolog, Haskell, OCaml, Scheme / Lisp, Python, Javascript, C--, Perl, PHP, C ++, Pascall, C, Fortran, Assembly


Non è stata definita la programmazione funzionale. Hai erroneamente implicato, "alcuni linguaggi dichiarativi 'puramente'", che la programmazione dichiarativa può essere impura . La programmazione dichiarativa richiede l'immutabilità dei valori memorizzati, la programmazione imperativa no. Vedere la mia risposta . L'immutabilità è la qualità "senza tempo" - vedi che il tuo dichiarativo factorialnon muta alcun valore.
Shelby Moore III,

3

Alcune buone risposte qui per quanto riguarda i "tipi" noti.

Propongo alcuni concetti aggiuntivi, più "esotici", spesso associati alla folla della programmazione funzionale:

  • Linguaggio specifico del dominio o programmazione DSL : creazione di un nuovo linguaggio per affrontare il problema in questione.
  • Meta-programmazione : quando il tuo programma scrive altri programmi.
  • Programmazione evolutiva : dove si costruisce un sistema che migliora continuamente se stesso o genera generazioni di sottoprogrammi successivamente migliori.

3

Penso che la tua tassonomia non sia corretta. Esistono due tipi opposti: imperativo e dichiarativo. Funzionale è solo un sottotipo di dichiarativo. A proposito, Wikipedia afferma lo stesso fatto.


+1: Sì, i paradigmi sono mele e arance.
Nikhil Chelliah,

FP non è "solo un sottotipo di dichiarativo". FP è ortogonale alla polarità tra imperativo e DP. DP richiede l'immutabilità dei valori memorizzati, FP impuro no. Wikipedia sta fondendo FP puro con FP, con l' assurda affermazione che i seguenti concetti sono "generalmente estranei alla programmazione imperativa": funzioni di prima classe, ricorsione, ordine di valutazione e tipizzazione statica. Quindi Wikipedia ammette "Programmazione funzionale in linguaggi non funzionali" impuri .
Shelby Moore III,

Wikipedia è sbagliata su questo punto. Molti linguaggi funzionali popolari consentono la programmazione in uno "stile dichiarativo", se si sceglie, ma non sono linguaggi dichiarativi. Ma lo stesso si potrebbe dire di C, dove puoi ancora programmare in uno stile funzionale se lo desideri, usando void * s.
Plynx,

Probabilmente, avrei dovuto essere più chiaro su questo punto, ma dall'altra parte, non avrei intenzione di rovinare l'antipasto di argomento con dettagli (imo) non abbastanza rilevanti. Vedo che i linguaggi funzionali tendono ad essere usati in modo dichiarativo. Puoi provare a scrivere in modo dichiarativo e / o funzionale in ASM o C oppure puoi probabilmente scrivere un programma imperativo in Lisp ma dubito che sarebbe molto utile o informativo per l'autore della domanda. Quindi, in sostanza, ritengo ancora adeguata la mia risposta, anche se potrebbe essere formulata diversamente.
Rorick,

2

In breve, più uno stile di programmazione enfatizza il Cosa (da fare) sottraendo i dettagli di Come (da fare) più tale stile è considerato dichiarativo. È vero il contrario per l'imperativo. La programmazione funzionale è associata allo stile dichiarativo.


Vedi i miei commenti sotto le altre risposte. FP non è sempre dichiarativo. What vs. how è la tassonomia sbagliata per IP vs. DP, poiché sia ​​DP che IP hanno una logica che coinvolge cosa e come.
Shelby Moore III,
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.