Puoi imparare la programmazione funzionale in C? [chiuso]


9

Come risultato della discussione di commento qui , mi chiedo se puoi imparare la programmazione funzionale in C?


30
Regardles di se è possibile o non è possibile, non si dovrebbe .
R. Martinho Fernandes,

27
Assolutamente! Il primo passo è scrivere un interprete Lisp ;-)
Ferruccio,

Se avessi capito bene, la domanda avrebbe dovuto riguardare l'apprendimento di vari concetti con lo pseudocodice, senza alcuna vera lingua.
SK-logic,

@ SK-logic: per dirla in parole povere, pochissimi programmatori hanno imparato a programmare solo con lo pseudocodice, la maggior parte ha dovuto sporcarsi le mani e le facce colpite dai messaggi di errore del compilatore / interprete.
sabato

4
@sbi, alcuni dei migliori programmatori hanno imparato la programmazione quando i compilatori non hanno ricevuto alcun messaggio di errore. La codifica su schede perforate richiede un po 'di comprensione di ciò che stai facendo molto prima che tu abbia la possibilità di eseguire il codice. E inutile menzionare che le basi per la programmazione funzionale erano state stabilite molto prima della costruzione di un primo computer.
SK-logic,

Risposte:


21

Ovviamente puoi fare la programmazione funzionale in C. In teoria, puoi anche imparare i principi di programmazione funzionale in C, ma il linguaggio non lo rende facile.

Presumo che tu abbia almeno un po 'di background in OOP; se lo fai, dovresti essere consapevole che OOP può essere fatto in C, incluso polimorfismo, getter / setter, regole di visibilità, ecc. ecc., ma è abbastanza doloroso farlo, e devi conoscere sia OOP che C all'interno- fuori per farlo fuori. È quasi lo stesso con FP.

Quello che dovresti fare è prima imparare un linguaggio di programmazione funzionale (la maggior parte di loro ha regole di sintassi sorprendentemente semplici; non è la sintassi che li rende difficili da imparare), quindi lascia che la tua saggezza appena acquisita influenzi il modo in cui scrivi C.


Come da richiesta, alcune cose che puoi imparare da FP e quindi applicare in, diciamo, C, C ++ o Java:

  • Evitare lo stato, in particolare lo stato mutabile condiviso
  • Apprezzo le funzioni pure
  • Apprezzo la valutazione pigra
  • Essere in grado di modellare in termini di verbi piuttosto che nomi
  • Essere in grado di affrontare i problemi in modo ricorsivo e iterativo
  • Utilizzo di funzioni di ordine superiore
  • Pensare alle funzioni come a un altro tipo di valore, che puoi trasferire e combinare con altri valori
  • Utilizzo di funzioni di prima classe come alternativa al polimorfismo basato sugli oggetti

1
Potete fornire esempi specifici di come i programmatori C / C ++ / Java possano trarre vantaggio dalla saggezza di LISP. In teoria ha senso, ma sto cercando qualcosa di concreto.
Giobbe

@Job, quale beneficio concreto può esserci? Espande le loro menti e forse li fa pensare a uno stato mutevole eccessivo come una cosa negativa, cosa si può chiedere di più?
dan_waterworth,

Quindi posso concludere da ciò che, mentre è possibile imparare (alcuni) FP in C, non ha senso farlo?
sbi,

@Job: ho imparato FP quando ho imparato LISP come studente molti anni fa. Circa un decennio dopo ho applicato FP nella meta-programmazione di template.
sbi,

1
@sbi, il mio modo preferito di apprendere nuove lingue e concetti è implementarli. E C è un linguaggio abbastanza decente per implementare un compilatore. Quindi, sì, puoi imparare FP con C.
SK-logic,

11

C può essere hackerato per offrire alcuni concetti funzionali:

Questa domanda StackOverflow ti dirà di più. Ma anche se sembra possibile fare una programmazione funzionale (o un ampio sottoinsieme di) in C, hack ed estensioni del compilatore e qualunque cosa non sia il modo migliore per imparare un concetto.

Per imparare davvero la programmazione funzionale, la soluzione migliore è uno dei principali linguaggi di programmazione funzionale come Lisp e i suoi dialetti ( Clojure , Scheme ), Erlang e Haskell . Ognuno di questi sono strumenti perfetti che funzionano all'interno della mentalità di programmazione funzionale. F # è anche un buon candidato se hai un background .Net, ma è un linguaggio multi paradigma, non strettamente un linguaggio di programmazione funzionale.


Come osserva tdammers nei commenti:

In realtà, LISP, clojure e schema sono anche multi-paradigma; Haskell, pur essendo puro e predefinito-pigro, consente anche una programmazione imperativa in un contesto monadico e ha un ampio supporto per l'elaborazione simultanea. Tutti questi hanno meccanismi che implementano gran parte della saggezza raccolta nel mondo OOP - incapsulamento, eredità, responsabilità individuale, composizione, ecc. riguarda quale paradigma costituisce il punto di partenza di una lingua.

Per quanto ne so , Lisp, i suoi dialetti ed Erlang sono candidati migliori di F # perché incoraggiano la programmazione funzionale su altri paradigmi, ciò che tdammer afferma magnificamente come punto di partenza di una lingua . F # comprende la programmazione funzionale ma non la incoraggia rispetto agli altri paradigmi supportati, la programmazione imperativa e oo.


Per quanto riguarda la tua ultima frase: in tal caso, direi che F # è un candidato migliore perché non ti intrappolerà in una mentalità funzionale. In un linguaggio multi-paradigma, quando inizi a martellare le viti, puoi semplicemente passare a un cacciavite. Quando sei intrappolato in un unico paradigma potresti perdere la differenza tra la vite e il chiodo.
R. Martinho Fernandes,

Bene, la domanda è su come imparare la programmazione funzionale, non la programmazione. Suppongo che l'op abbia una certa esperienza in un linguaggio multi paradigma e desideri il modo più efficiente per imparare la programmazione funzionale, nel qual caso F # è un buon candidato ma non perfetto. Intrappolato in un singolo paradigma è ovviamente il modo migliore quando stai cercando di imparare quel singolo paradigma poiché non devi affrontare tutto ciò che non lo è.
yannis,

Credo che apprendere quando il paradigma è adatto e quando è inadatto a un determinato compito fa parte dell'apprendimento, forse il più importante.
R. Martinho Fernandes,

4
In realtà, anche LISP, clojure e schema sono multi-paradigma; Haskell, pur essendo puro e predefinito-pigro, consente anche la programmazione imperativa in un contesto monadico e ha un ampio supporto per l'elaborazione simultanea. Tutti questi hanno meccanismi che implementano gran parte della saggezza raccolta nel mondo OOP - incapsulamento, eredità, responsabilità individuale, composizione, ecc. riguarda quale paradigma costituisce il punto di partenza di una lingua.
tdammers,

2
@MartinhoFernandes: Si potrebbe sostenere che essere intrappolati in un unico paradigma è il modo perfetto per imparare quando è davvero un dolore nel culo :-)
Jörg W Mittag,


2

TL; DR

La programmazione funzionale riguarda le chiusure e le loro applicazioni. A meno che qualcuno non sia in grado di mostrarti una libreria di chiusura di discesa per C, dimentica di usare C per imparare la programmazione funzionale.

Cos'è la programmazione funzionale?

Il concetto cardine della programmazione funzionale è la nozione di chiusure che, in termini approssimativi, catturano una funzione insieme a associazioni di variabili. Oltre all'uso pervasivo delle chiusure, ci sono alcuni altri tratti distintivi nella programmazione funzionale, come l'uso di funzioni ricorsive e valori immutabili (entrambi giocano bene insieme). Questi tratti sono più un problema culturale che altro, e non esiste alcun ostacolo tecnico per usarli praticamente in qualsiasi lingua, per questo mi concentro sulle chiusure nella mia risposta: non tutte le lingue consentono di creare facilmente chiusure.

Tre illustrazioni sull'utilità delle chiusure

Un uso tipico delle chiusure è l'implementazione di meccanismi di privacy. Ad esempio il codice Javascript - negli esempi ho scelto Javascript perché è un linguaggio funzionale con una cosiddetta "sintassi simil-C" e la tua domanda suggerisce che hai familiarità con C:

create_counter = function()
{
  var x = 0;
  var counter = function()
  {
    ++x;
    return x;
  };
  return counter;
}

Quindi con

a = create_counter();
b = create_counter();

abbiamo due funzioni ae contiamo braccolte disgiunte. Il punto dell'esempio è che le variabili xvengono catturate dalla chiusura che definisce la counterchiusura e ogni volta che una nuova counterchiusura is instantiated by the function, it gets its fresh own idea of whatè x`.

Un altro uso tipico delle chiusure è la definizione di applicazioni parziali di funzioni. Supponiamo che abbiamo una struttura di reporting simile syslogall'implementazione di una funzione

var log = function(priority, message) {

};

dove gli argomenti prioritye messagesi pensano che siano stringhe, il primo è uno dei "debug", "info"e così via. Possiamo definire una fabbrica di tronchi come questa:

var logWithPriority = function(priority) {
  return function(message) {
    log(priority, message);
  };
};

e utilizzarlo per definire versioni specializzate della nostra funzione di registro:

var debug = logWithPriority("debug");
var info = logWithPriority("info");

Questo è molto utile, perché invece di scrivere in forquesto modo soggetti a errori

for(i = 0; i < journal.length; ++i) {
   log("info", journal[i]);
}

possiamo scrivere in modo più pulito, più breve e molto più semplice (non c'è i, è molto meglio):

journal.forEach(logWithPriority("info"));

Un terzo importante campo di applicazione delle chiusure è l'implementazione della valutazione pigra - si noti che il supporto linguistico speciale può fornire una migliore implementazione.

Una funzione pigra, invece di eseguire un calcolo diretto, restituisce una chiusura che può essere chiamata (o "forzata" nel gergo della pigrizia) per eseguire la domanda. La motivazione per fare ciò è che separa la preparazione di un calcolo e l'esecuzione di un calcolo. Un esempio pratico di ciò è la compilazione di espressioni regolari: se un programma compila molte espressioni regolari al momento dell'avvio, avrà bisogno di molto tempo per avviarsi. Se invece compiliamo pigramente le espressioni regolari e le forziamo quando ne abbiamo bisogno, allora il nostro programma può iniziare rapidamente. Naturalmente, le espressioni regolari possono essere sostituite qui con qualsiasi struttura che richieda un considerevole tempo di inizializzazione.

Ecco come implementare la valutazione pigra con le chiusure. Considera l'implementazione classica della funzione arrayMax che restituisce il massimo in un array:

function arrayMax(array) {
  return array.reduce(function(a, b) {
    return Math.min(a, b);
  };
}

La variante pigra sarebbe:

function arrayMax(array) {
  var memo = null;
  function actuallyCompute() {
    if(memo === null) {
      memo = array.reduce(function(a, b) {
        return Math.min(a, b);
      });
    }
    return memo;
  }
  return actuallyCompute;
}

Il valore restituito è una chiusura che può essere utilizzata per calcolare il valore o recuperarlo un'altra volta se è già stato calcolato.

Con questi tre esempi, dovremmo essere certi che le chiusure e le loro applicazioni sono il nucleo della programmazione funzionale.

Conclusione

Imparare la programmazione funzionale significa imparare a programmare con le chiusure. Di conseguenza, le lingue che consentono la facile manipolazione delle chiusure, e in particolare l'applicazione parziale delle funzioni, dovrebbero essere considerate quando si cerca una lingua per studiare la programmazione funzionale. Al contrario, le lingue in cui le chiusure non possono essere facilmente manipolate sarebbero scelte sbagliate.


1
Grazie per questo bel campione. A proposito, come definisci var info, non sarebbe journal.forEach (info)?
ejaenv,

Sì, sarebbe una variante appropriata! :)
Michael Le Barbier Grünewald,

1

Penso che gli strumenti che usi influenzino molto il tuo apprendimento. È quasi impossibile imparare concetti di programmazione per i quali il linguaggio di programmazione che usi non fornisce i mezzi per farne uso. Certo, puoi sempre imparare alcune cose, ma non puoi impararlo correttamente.

Ma questo è comunque accademico, perché, come afferma Martinho nel suo commento , anche se potessi imparare la programmazione funzionale, non dovresti provare a farlo, perché ci sono lingue in cui questo è molto più semplice.


1

Non dovresti imparare la programmazione funzionale in C, ma in un linguaggio funzionale rigoroso (Haskell, Caml, Erlang, ecc.).

Se sei nuovo al funzionale, non lo otterrai mai con un linguaggio non funzionale. Più probabilmente, ti allenerai per fare ciò che pensi sia una programmazione funzionale e apprendere le cose nel modo sbagliato. Ed è sempre più difficile «riapprendere» le cose nel modo giusto piuttosto che impararle nel modo giusto all'inizio.

Comunque, penso che fare funzionale in C sia un buon esercizio per qualcuno che già conosce funzionale. Perché quella persona imparerà cosa sta succedendo dietro il cofano - cosa sta realmente facendo il computer.

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.