La programmazione funzionale aggiunge complessità al codice? [chiuso]


17

Per tutto l'anno passato ho scritto il codice Scala (proveniente da un background Java). Mi è piaciuto molto come potresti creare un codice più semplice e più pulito, con vals, classi di case, funzioni map / filter / lambda, impliciti e inferenza del tipo. L'ho usato principalmente per un'applicazione basata su Akka .

Quest'anno sono su un progetto Scala con un nuovo team, a cui piace molto la programmazione funzionale. Usano pesantemente Scalaz e il codice è riempito ovunque di applicativi, limiti di contesto, lettore / scrittore / monade di stato, anche il metodo principale è "avvolto" in una monade I / O. Il loro ragionamento è che questo fa sì che il compilatore "funzioni per noi" affermando che il codice è corretto e che ogni funzione è priva di effetti collaterali.

Anche così, dal mio punto di vista tutta questa sintassi interferisce davvero con la logica aziendale. Ad esempio, un tipo di "MyBusinessObject" va bene, così come tipi come "Elenco [MyBusinessObject]", "Opzione [MyBusinessObject]" o anche "Future [MyBusinessObject]". Tutti hanno un significato e uno scopo chiari. D'altra parte, codice come:

def method[M[_]: Applicative] = {
  case (a, b) => (ca[M](a) |@| cb[M](b)) {
    case t @ (ra, rb) =>
      if (ra.result && rb.result) t.right
      else t.left
  }
}

aggiunge complessità al programma o sono solo io che non sono abituato a questo modo di programmare?


6
Qual è la tua domanda obiettivamente rispondente?
Deer Hunter

1
Sembra che porti a una tonnellata di codice con nomi di variabili di una o due lettere. Sembra un po 'APL. Questo non è un complemento.
user949300

3
Ho iniziato a suonare con Haskell l'anno scorso. Sembrava incredibilmente complesso al tempo, quando non capivo concetti come curry, funzioni, monadi, ecc. Haskell è simile a Scalaz in quanto ha molte funzioni simboliche brevi, come >>=e <$>, che non significano nulla fino a quando sapere cosa fanno. Dopo aver appreso cosa significano, tuttavia, ora mi leggono in modo molto naturale e rapido. Non proprio una risposta, solo la mia esperienza oggettiva con cose come questa. Uso anche Scala, ma non ho esperienza con la libreria Scalaz.
KChaloux,

3
Non hai familiarità con gli idiomi. @ user949300 Le variabili brevi non sono realmente un problema per molti codici funzionali (pensate alle convenzioni di stile matematico!). Leggi anche il blog di Tony Morris per una discussione più approfondita di ciò che meglio trasmette significato, tipi o nomi di variabili prolissi.
Andres F.

3
@ user949300: i nomi di variabili brevi sono preferiti localmente, è lo stesso nei mondi funzionale e imperativo (non scriveresti for(i=0; i<7; ++i) { trivialOperation(i); }con qualche trivialOperationCountvariabile scomoda , vero?) Ora, i linguaggi di programmazione funzionale con la corrispondenza dei modelli a volte introducono alcune più variabili in cui tu scrivere semplicemente le chiamate al metodo accessor in OO. Il risultato è generalmente più conciso; forse un po 'meno autoesplicativo, ma cercare la dichiarazione dei dati normalmente lo chiarisce rapidamente. La digitazione statica aiuta molto, non è come in APL.
leftaroundabout

Risposte:


37

Questo non ha nulla a che fare con la programmazione funzionale - è possibile trovare questo tipo di situazione nel contesto di qualsiasi altro linguaggio di programmazione - gli sviluppatori che amano così tanto i costrutti avanzati del "loro" linguaggio da ignorare qualsiasi senso comune di leggibilità e semplicità. Ho riscontrato una situazione del genere in C, C ++, Perl, Java, C #, Basic e altri linguaggi non funzionali. Non è la programmazione funzionale che aggiunge complessità al codice, come fanno i programmatori.

Non fraintendetemi, non consiglio di evitare funzionalità linguistiche avanzate, ma è importante trovare il giusto equilibrio in un determinato contesto. Quando si scrive una libreria generica per l'utilizzo di> 100.000 sviluppatori in tutto il mondo, ci sono diverse misure da applicare come quando si sta scrivendo un singolo generatore di report solo per l'ufficio locale.


7
Ha anche molto a che fare con la comunità. Per uno sviluppatore con uno sfondo Java o C #, il codice è a malapena comprensibile (e neanche la sua comunità lo capirà). Ma se scrivi Haskell, per esempio, e non usi monadi, applicativi, funzioni e così via, stai sconcertando la comunità di quel linguaggio. La "naturalezza" del codice non è inerente, ma relativa alla sua comunità e alle pratiche consolidate.
Andres F.

1
Questo è difficile da vedere perché la maggior parte di noi proviene da ambienti imperativi, il che a volte ci porta a fare ipotesi sbagliate su ciò che è naturale.
Andres F.

basta guardare la libreria SLT C ++, che potrebbe essere scritta per essere molto più leggibile per il dilettante
maniaco del cricchetto

@ratchetfreak: immagino tu intenda STL. Penso che questo sia un ottimo esempio (e in effetti, avevo questo in mente nella mia risposta). L'uso della meta-programmazione template ha molto senso quando sei un programmatore STL, perché rende l'STL più riutilizzabile. E le persone che devono mantenere quel codice vengono normalmente utilizzate anche per la metaprogrammazione dei modelli. L'uso della metaprogrammazione dei modelli in modo simile a STL in tutte le applicazioni aziendali standard può facilmente portare a codice complicato e difficile da mantenere. Si possono sicuramente trovare casi (rari) in cui TMP va bene anche in applicazioni aziendali, di corsi.
Doc Brown,

@DocBrown sì, la dislessia è iniziata nel momento sbagliato, ma onestamente se avessi una mezza idea (e molto più tempo di quello che ho ora) potrei riscrivere molti dei corpi funzionali per essere molto più leggibili.
maniaco del cricchetto,

7

Direi che non ti sei abituato al modo in cui codificano è almeno parte dell'immagine. Sono in una situazione simile alla tua (vengo da C # in F # e lavoro con persone con background Haskell), e mentre la trovo un'esperienza interessante, ho dei momenti in cui sbatto la testa contro il muro, districando un composizione di funzioni senza punti particolarmente contorta solo per capire cosa sta succedendo lì. È una cosa culturale.

Non so se questo particolare codice aggiunga complessità al programma. Concordato che un pezzo generico di codice può essere complesso stesso. Ma è un'utilità, non una parte della logica aziendale. Se vuoi sapere se rende la base di codice più complessa o più semplice, dovresti immaginare come dovrebbe apparire senza quel pezzo di codice. È spesso il caso di costrutti così generici che sono essi stessi complessi, ma è una complessità che puoi adattare su un singolo schermo. Allo stesso tempo, rendono l'intera base di codice un po 'più semplice. Questo è particolarmente vero per le monadi.

Inoltre, può anche essere un caso di "arte per l'arte", come suggerisce @ Brown Brown. Non posso escluderlo neanche.


5

Direi che in generale la programmazione funzionale riduce la complessità eliminando lo stato mutabile, riducendo così il numero di casi che devono essere considerati quando si cerca di capire come funziona una sezione di codice.

Tuttavia, la programmazione funzionale rende possibili gradi più elevati di astrazione e, sebbene un codice altamente astratto possa essere estremamente utile, può anche essere difficile da capire perché è per definizione divorziato dal contesto che normalmente useresti per guidare la tua comprensione. Il tuo commento "Tutti hanno un significato e uno scopo chiari" sugli oggetti di business è senza dubbio vero, ma è in realtà un riflesso del fatto che quella logica è molto specifica per un'esigenza e un contesto che già capisci. L'esistenza di un costrutto come Monade ti consente di fare qualcosa di molto utile con poco sforzo, ma il web è disseminato di pagine che cercano di spiegare cos'è una Monade. Questa è astrazione per te.

Inoltre, Scalaz è stato scritto da persone che avevano mangiato e respirato FP per lungo tempo; volevano portare la funzionalità disponibile in Haskell alla Scala. In tal modo non fecero alcun tentativo di essere pedagogici. Scalaz fa uso di un vocabolario e di uno stile che sembrano chiari e chiari per gli autori ma estranei ai non iniziati. I metodi che sono sconcertanti per il resto di noi sembravano così ovvi agli autori, dato il loro background di Haskell, che non meritavano nemmeno un commento.

Inoltre, come linguaggio di programmazione funzionale Scala ha alcune carenze (in parte perché la JVM ha carenze) che hanno costretto gli autori di Scalaz a scrivere codice più brutto in alcuni casi. Ad esempio, la mancanza di eliminazione generale delle chiamate di coda impone l'uso di trampolini in alcuni codici e la mancanza di un "sistema di tipo" può complicare le firme di tipo.

E infine, Scalaz fa un grande uso di se stesso. Questo potrebbe essere pensato come un segno del suo potere, ma per chi non lo sapesse può trasformare la fonte in un enigma - qualsiasi pezzo di codice casuale che guardi probabilmente farà uso di qualcos'altro che ti sembra estraneo.

Tenere duro. E questo potrebbe aiutare.


-4

Aggiunge complessità al programma o è solo che non sei abituato a questo modo di programmare?

Perché pensi che queste possibilità non siano la stessa cosa?

Il codice ben scritto può essere letto da persone che non hanno familiarità con il linguaggio di programmazione specifico. Alcune lingue (BASIC, Pascal, ecc.) Possono essere lette e comprese da bambini che non hanno mai visto linguaggi di programmazione prima d'ora.

Se qualcuno che ha esperienza con altre lingue ed esperienza con Scala (e che presumo abbia lavorato con Scalaz per almeno una settimana e abbia colleghi per spiegare le cose più difficili) è ancora confuso; allora questa è la prova che ha aggiunto complessità.


11
Questo semplicemente non è vero:"Well written code can be read by people who aren't familiar with the specific programming language."
Andres F.

@Andres: è vero ... fino a un certo punto. Un codice ben scritto separerà la logica aziendale dai dettagli di implementazione e la logica aziendale dovrebbe essere leggibile, poiché la maggior parte di ciò che sta facendo è effettuare chiamate dirette a funzioni di supporto ben definite. Questi aiutanti possono usare tutti i tipi di funzionalità linguistiche, ovviamente, e richiedono una forte esperienza con la lingua e le biblioteche per capire.
Ben Voigt,

4
Credo che quanto segue è APL idiomatica: x[⍋x←6?40]. Cosa pensi che faccia? Di sicuro non lo avrei saputo ...
Bdesham,

3
@Brendan Solo all'interno dello stesso paradigma (e anche allora, a volte no). Ad esempio, Prolog, Java e APL sono così diversi che direi che se conosci solo una di quelle (e nessuna altra lingua), non puoi leggere le altre due, indipendentemente da quanto conosci la prima. (Seriamente, nell'esempio di bdesham, come diavolo dovresti interpretare "albero di natale" se non conosci nessun APL?)
Izkata

1
Brendan, la tua definizione di ben scritto non è standard. Ben scritto è sempre relativo alla lingua e alla sua comunità. Un programma in lingua X è ben scritto se non è buggy, è efficiente e chiaro ... per il pubblico dato! Questo vale per la lingua scritta in generale, a proposito: conosci sempre il tuo pubblico. Ciò che è adatto per (diciamo) un documento scientifico probabilmente non è adatto per una e-mail a tua madre.
Andres F.
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.