La programmazione funzionale è solo diversa o è davvero più dura?


12

La programmazione funzionale è solo diversa o è davvero più dura ?

Di 'a qualcuno che non ha mai imparato la programmazione prima e gli viene insegnato la programmazione funzionale. vs qualcuno che non ha mai imparato la programmazione prima, e gli viene insegnato la programmazione imperativa. quale troverà più duro? o lo stesso?

La mia domanda: dire che il problema ora è quello di inserire un input nel caso cammello,

tale che qwe_asd_zxc_rty_fgh_vbndiventaqweAsdZxcRtyFghVbn

Il modo procedurale è:

  1. dividerlo lungo il _
  2. passa in rassegna l'array saltando il primo elemento
  3. per ogni voce capitalizziamo la prima lettera
  4. unire i risultati insieme

Il modo funzionale è:

  1. se non riesci a trovare il _resoinput
  2. tagliare il inputlungo il primo _(tale che otteniamo qwee asd_zxc_rty_gfh_cvb)
  3. capitalizzare la prima lettera di heade concatenela conf(tail)

Ok, se hai un background funzionale E hai una notevole esperienza nella programmazione procedurale, vorrei chiederti: ci vorrà più tempo per capire il modo procedurale o ci vorrà più tempo per capire il modo funzionale?

Se hai un background procedurale ma hai molti anni di esperienza con la programmazione funzionale, vorrei porre la stessa domanda: ti ci vorrà più tempo per capire il modo procedurale o ci vorrà più tempo per capire il funzionale modo?


5
Ehrm, il "modo procedurale" mi sembra perfettamente funzionale se usiamo mapper il passaggio 3 invece di un ciclo mutante. Il secondo approccio è qualcosa che prenderei in considerazione solo se non esiste una funzione split nella libreria standard (nel qual caso dovrebbe essere confrontata con una soluzione imperativa che anche non utilizza split).
sepp2k,

8
Non c'è nulla di specificamente funzionale o procedurale in nessuno dei tuoi esempi. Mi sembra che tu stia cercando di estrapolare da una comprensione errata della programmazione funzionale. Non c'è da stupirsi che tu stia ottenendo risultati insoliti.
Rein Henrichs,

Non penso che la programmazione funzionale sia dura, è solo diversa. Se non si ha alcuna esperienza di programmazione, è altrettanto facile da imparare, ma per qualche motivo una volta appreso la programmazione imperativa, la programmazione funzionale diventa difficile.
dan_waterworth,

1
Penso che la distinzione tra funzionale e procedurale diventi discutibile, poiché i linguaggi mainstream come JavaScript, C #, Groovy contengono sempre più funzionalità funzionali.
user281377

2
La programmazione imperativa è molto più difficile e controintuitiva per coloro che non avevano precedenti esperienze di programmazione. Un'espressione simile x=x+1può far esplodere un cervello inaspettato. La programmazione funzionale è naturale, non è altro che funzioni puramente matematiche strettamente e comoda.
SK-logic,

Risposte:


12

Solo diverso. La programmazione funzionale è molto più strettamente correlata alla matematica, che la maggior parte delle persone conosce. L'intera cosa delle "variabili immutabili" è solo uno shock per i programmatori imperativi in ​​cui la mentalità "mutabile" è profondamente radicata.

Per i nuovi arrivati, è spesso abbastanza intuitivo che non puoi semplicemente cambiare il valore di qualcosa.

Dove ho studiato CS, ci è stato insegnato un linguaggio funzionale come il nostro primo corso. E tutti quelli che avevano imparato C ++ o Java in precedenza avevano avuto delle difficoltà. Coloro che non conoscevano la programmazione lo raccolsero abbastanza facilmente.


jalf sei uno di quelli che non conoscono la programmazione e l'hai acquisito abbastanza facilmente?
Pacerier,

Ero da qualche parte nel mezzo. Avevo cercato un po 'di tempo con C ++ e alcuni PHP prima di allora, ma non abbastanza per abituarmi davvero alla mentalità imperativa. Lo schema era abbastanza chiaro quando guardavi la classe nel suo insieme. Inoltre, è stato quasi un decennio fa, quindi no, non sono del tutto nuovo nella programmazione di oggi;)
jalf

Variabili immutabili? La matematica non è un linguaggio di programmazione funzionale? le variabili in matematica sono sicuramente mutabili, no?
user56834

20

È solo diverso

Quando programmate essenzialmente traducete il modo in cui ragionate in codice, si potrebbe dire che la distanza tra i vostri pensieri e la soluzione finale sia il "gap cognitivo". Maggiore è il divario, più difficile sarà per te colmare.

Se vieni da un background procedurale, ti sarai allenato a pensare in modo procedurale, quindi il divario sarà inferiore rispetto al codice funzionale e viceversa.

L'unico modo per un paradigma di programmazione di essere intrinsecamente più semplice di qualsiasi altra cosa sarebbe se fosse mappato a qualcosa che già conoscevi, come il linguaggio ordinario, in modo da iniziare con un divario più breve.

Funzionale e procedurale è comunque un concetto piuttosto fluido e tendono a sovrapporsi


4

Sì, la programmazione funzionale tende a essere difficile da comprendere per molte persone (tendo a dirlo, specialmente quelli che sono già stati prima esposti alla programmazione procedurale).

Direi anche che il tuo esempio di programmazione funzionale non è in realtà un ottimo esempio di programmazione funzionale. Sta usando la ricorsione e sta solo componendo un risultato invece di modificare lo stato, ma non molto di più.

Per ottenere un esempio migliore di programmazione funzionale, considera un problema più generale: piuttosto che "cercare un carattere di sottolineatura e convertire la lettera successiva in maiuscolo", considera questo come solo un caso speciale di ricerca di un modello ed esecuzione di un codice arbitrario quando è stato trovato.

Molte lingue lo supportano, ma per farlo richiedono che specifichiamo il modello come qualcosa di simile a un'espressione regolare. Le espressioni regolari, tuttavia, non sono altro che un linguaggio di programmazione per scopi specifici e un'implementazione di RE è un compilatore e / o interprete per quel linguaggio. Il risultato della compilazione di RE è fondamentalmente una funzione che viene eseguita (in una speciale macchina virtuale RE) per abbinare l'espressione a qualche input.

In qualcosa come Perl, usi un linguaggio speciale per specificare il modello e un compilatore speciale per convertire quella stringa in una sorta di cosa simile a una funzione, e un interprete speciale per prendere quella cosa simile a una funzione per eseguirla. In un linguaggio funzionale, in genere si utilizza il linguaggio stesso per specificare il modello e si utilizza il compilatore del linguaggio stesso per produrre una funzione reale . Siamo in grado di generare quella funzione al volo (circa come se potessimo compilare una RE quando vogliamo), ma quando lo facciamo, il risultato può essere eseguito come qualsiasi altra funzione nella lingua invece di aver bisogno di cose RE speciali per farlo.

Il risultato è che siamo in grado di generalizzare il problema di cui sopra in modo relativamente semplice. Invece di codificare "_" e "maiuscole" direttamente nella trasformazione, tuttavia, possiamo avere qualcosa del tipo:

s&r(pattern, transform, string) {
    if (!pattern(string))
        return string
    else
        return transform(matched part of string) + s&r(rest of string);
}

Ma, a differenza di qualcosa in cui specifichiamo il pattern come RE, possiamo specificare il pattern direttamente come una funzione reale, e ancora usarlo, qualcosa come:

my_pattern(string) return beginning(string) == '_';

E poi passiamo quella funzione a s & r. In questo momento, è una funzione piuttosto banale e l'abbiamo codificata interamente staticamente. Un linguaggio funzionale diventa in gran parte interessante quando lo usiamo come possiamo RE, e generiamo una funzione completamente nuova al volo basata su qualcosa come l'input dell'utente, ma a differenza di un RE quella funzione non ha bisogno di un interprete RE speciale per funzionare - è solo una funzione normale come qualsiasi altra.


4

Ecco il codice completo in Racket :

;; camelize : string -> string
(define (camelize str)
  (let ([parts (regexp-split #rx"_" str)])
    ;; result of regexp-split is never empty
    (apply string-append
           (first parts)
           (map string-titlecase (rest parts)))))

(camelize "qwe_asd_zxc_rty_fgh_vbn")
;; => "qweAsdZxcRtyFghVbn"

Come programmatore funzionale con esperienza procedurale, non penso che mi occorrerebbe più tempo per "capire" una soluzione procedurale, ma certamente mi ci vorrebbe più tempo per scriverla.

A proposito, l'esito previsto nell'esempio nel post originale è errato: manca una "h" verso la fine.


gd per averlo sottolineato. a cura
Pacerier

3

La mia teoria sugli animali domestici è che i modelli di programmazione sono più facili da capire quanto più si avvicinano al funzionamento effettivo dei computer. I puntatori sono difficili da capire fino a quando non ti rendi conto che sono essenzialmente indirizzi di macchine. La ricorsione è difficile da capire fino a quando non si è passati consapevolmente a un piccolo esempio, si sono visti i frame dello stack e si è realizzato dove sono memorizzati i diversi valori della stessa variabile. Ciò non significa che la programmazione degli assemblatori sia più semplice della programmazione di alto livello, ma aver visto come è fatto fa miracoli per il modello mentale che è la chiave della competenza, sia nella programmazione che nell'usabilità generale.

Ora, il modello procedurale è un po 'più vicino alla solita architettura della macchina: le assegnazioni sono scritture di memoria (o registro). Le chiamate di procedura sono in realtà solo salti fantasiosi, in ifrealtà è un salto condizionale, ecc. Ma in Lisp, ad esempio, non esiste un semplice equivalente di basso livello a un legame lessicale o un'espressione lambda. Comprenderlo richiede di immaginare una macchina funzionale astratta completamente separata tra il livello del linguaggio e la macchina fisica, perché e apparentemente la maggior parte delle persone non arriva mai così lontano.

(I sono familiarità con l'idea che l'architettura di von Neumann è in ultima analisi arbitraria, e non dobbiamo menti principianti pregiudizio di con tali dettagli irrilevanti di architettura della macchina, e invece direttamente far loro conoscere la semantica dei linguaggi di programmazione. In realtà, ho ho tenuto personalmente alcuni di questi corsi, ma sempre più ritengo che questo sia un obiettivo nobile ma fuorviante; le persone imparano la programmazione costruendo la comprensione dal basso verso l'alto e la strada per la programmazione funzionale è semplicemente un po 'più lunga.)


7
Secondo questa logica, l'Assemblatore dovrebbe essere la più semplice di tutte le lingue da imparare :)
Homde,

4
La programmazione funzionale è abbastanza facile da capire se ci si arriva dalla giusta direzione. La "macchina funzionale astratta" di cui parli è semplicemente algebra . La valutazione viene effettuata mediante riscrittura dei termini; l'applicazione della funzione viene eseguita per sostituzione. I programmatori imparano a risolvere i problemi utilizzando gli stessi strumenti che hanno già visto in anni di lezioni di matematica. Se inseguono CS, c'è abbastanza tempo per incontrare la pila di tartarughe più tardi; in caso contrario, hanno ancora imparato utili capacità di problem solving e principi di progettazione. Dai un'occhiata a Come progettare i programmi .
Ryan Culpepper,

2
@mko No, secondo questa logica i bytecode attuali 011011001001101...sarebbero la lingua più semplice da imparare!
MarkJ,

2
@konrad: l'assemblatore RISC È probabilmente la lingua più semplice da imparare. Sapere come farlo fare qualcosa di utile è un'altra storia tutti insieme ...
Bryan Boettcher,
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.