Ahhhh ti sento già urlare e sospirare: “Altri post sulla programmazione funzionale, qual è il problema? Perché dovrei cambiare il mio modo di pensare, adesso?”
Prova a ribaltare queste domande e chiediti: stiamo parlando di programmazione qui, forse perché ti aiuterà?
Forse può rendere il tuo codice più facile da leggere e più manutenibile?
Sei tranquillo, ora? Va bene, affrontiamo alcune "paure" (anche se non dovrebbero essere) sulla programmazione funzionale (FP), vero?
Poiché Javascript si sta trasformando sempre più in un linguaggio Assembly per browser, ci sono diverse librerie/framework che utilizzano i principal FP, inoltre il codice scritto in quei linguaggi viene compilato in JS per essere utilizzabile in tutti i browser.
Noi useremo puro copione nei nostri esempi poiché è più conciso e più facile da leggere rispetto a JS puro.
Introduzione di base ai termini e al paradigma FP (Utilizzo di Purescript VS Pure JS)
In primo luogo, vorrei farti familiarizzare con alcuni concetti di base su FP. Programmazione Funzionale, Come suggerisce il nome,
si basa sul Paradigma Funzionale (non dici?) dove tutto è a Funzione, quelle funzioni che amiamo dalla matematica (parola trigger), ricordi? Da A a B, o da Integer a Integer lo chiami.
Esempio:
addMeFive::Int -> Int addMeFive x = x + 5
vs
function addMeFive(x) {
return x + 5
}
Se ricordi bene, le funzioni, per definizione, quando si riceve lo stesso input più e più volte lo faranno
restituisce sempre lo stesso risultato (Pure funzioni).
addMeFive 5 = 10 -- e non c'è modo di ottenere altre risposte da questa chiamata.
Questi piccoli amici hanno proprietà interessanti come la composizione, che è la base per creare programmi più complessi in FP.
La composizione non è l'unico modo per incollare insieme le funzioni
Composizione delle funzioni f e g.
g::a -> b f::b -> c
Se esiste una funzione da a a b e un'altra da b a c allora esiste anche una funzione da a a c e può essere definita dalla composizione delle due ultime funzioni.
-- f <<< g legge - f dopo g f <<< g :: a -> c
Le variabili sono immutabile, per difetto o in caso negativo, deve essere chiaramente indicato.
a=5 a=8 -- non è consentito.
Come probabilmente puoi vedere, se le variabili sono immutabili, le condizioni di gara non sono un problema poiché ne è una conseguenza
di stato mutevole. Quindi, in FP, la concorrenza e il funzionamento parallelo sono più facili da gestire.
Tipi sono estremamente importanti nella programmazione funzionale.
Non tutti i linguaggi di programmazione funzionale sono fortemente tipizzati, i tipi ci incoraggiano, tuttavia, a pensare prima alle relazioni nel nostro software invece di sprint e codificare senza pensare.
Un tipo speciale di tipi sono i tipi polimorfici. Polimorfismo ci consente di utilizzare la stessa funzione ma con diversi tipi di input, questi tipi hanno costruito la pietra angolare per i tipi generici noti nei linguaggi OOP come Java, C# e così via.
length::[a] -> Int -- restituisce la lunghezza di un List di tipo a
Dopo le basi, uno degli aspetti importanti della programmazione funzionale è Funzioni di ordine superiore (HOF).
È qui che le funzioni diventano interessanti, sappiamo che le funzioni ricevono un input e restituiscono un output, fino ad ora erano solo interi, stringhe, un tipo casuale a, ecc.
E se diamo una funzione come argomento? Ecco fatto, hai appena aggiornato la tua funzione.
Esempio:
mappa:: (a->b) -> [a] -> [b]
map è una funzione che restituisce una lista in cui la funzione data come argomento è stata applicata a ciascun elemento della lista data.
mapè una funzione piuttosto importante, quindi tienila a mente.
Astrazione: OOP vs FP

Definizione di Astrazione (che meglio si adatta a Computer Science): "La qualità di affrontare le idee piuttosto che gli eventi".
Non vogliamo affrontare eventi concreti o dettagliati perché ci sono troppi fattori che bloccheranno il nostro modo di pensare, quindi astraiamo, perdendo alcuni dettagli ma mantenendo il focus del problema (le idee della definizione) .
Aspetta cosa?
Per essere più concisi, selezioniamo manualmente le parti più importanti del nostro problema e i dettagli rimanenti vengono dimenticati, facilitando non solo la struttura per i nostri tipi/oggetti ma anche i nostri programmi generali.
In OOP, l'astrazione si ottiene semplicemente rappresentando "Cose", sebbene, non in tutta la sua complessità,
solo le proprietà importanti. Quindi puoi fare "Roba" con l'entità astratta, ed è praticamente tutto.
A proposito, la "Cosa" si chiama Oggetto e "Roba" è Metodo.
In FP, cerchiamo di massimizzare l'astrazione, tagliamo i nostri problemi in funzioni semplici che verranno successivamente composte per creare funzioni più complesse risultando in un programma che fa ciò che volevamo. Non si concentra solo sulla rappresentazione delle "Cose", ma riguarda più le relazioni tra di loro, che in definitiva è il nostro obiettivo. Creiamo i nostri tipi di base e poi, se abbiamo bisogno di tipi più complessi, possiamo combinarli con vari operatori es. A + B (O A o B o Union Type), A x B (A volte B, O la coppia tipo) e pochi altri.
Modelli FP 101
Eccoci qui, il vero punto di tutto questo divagazione, Modelli FP, da non confondere con i Design Pattern di OOP, i pattern FP riguardano il riconoscimento della ripetizione, sai, il vero significato dei pattern (devi provare più duramente l'OOP).
Parliamo quindi di Currying, Functors, Catamorphism e Anamorphism (o rispettivamente, curry, Mappa, piega and Unfold). Per semplicità, userò Liste per spiegare gli ultimi tre:
curry
Curry (non il piatto) è ciò che facciamo quando trasformiamo funzioni con più di un argomento in funzioni che ricevono un argomento e quindi restituiscono una funzione responsabile della ricezione degli argomenti rimanenti. Ciò facilita la possibilità di composizione/concatenamento.
curry :: ((a,b)->c) -> a -> b -> c
Mappa alias Functor
Mappa aka funtore è l'applicazione di una funzione in una struttura complessa. Per gli elenchi, sembra:
mappa:: (a->b) -> [a] -> [b]
es. Quando vuoi raddoppiare gli elementi di una lista, invece del buon vecchio ciclo for, perché no:
map((elem)=> elem*2)[1,2,3]=map(*2)[1,2,3]=[2,4,6]
Riduci aka Catamorphism aka Fold
Catamorfismo dal greco: κατά “verso il basso” e μορφή “forma, forma” o anche noto piega è la capacità di ridurre una struttura in un'altra struttura, nota anche come il Conquistare da Dividere e conquistare.
piega::pertutto abc . (a->b->b) -> b -> [a] -> b
es. Vuoi calcolare la somma di un elenco di numeri interi? Nessun problema
piega ((elem,acc)=> acc + elem) 0 [1,2,3] = 6
Per essere più espliciti, fold è la funzione ricorsiva con l'elenco dei tipi di input e l'output di qualsiasi tipo desideri. Se decostruiamo il nostro esempio nella funzione corrispondente:
sum::[int] -> int sum[] = 0 -- secondo argomento del nostro fold sum (x:xs) = x + sum xs -- stesso comportamento delle funzioni ricevute come argomento nel nostro esempio fold
Genera aka Anamorfismo aka Unfold
Anamorfismo dal greco ἀνά “verso l'alto” e μορφή “forma, forma” o noto anche come Unfold è la capacità di generare una struttura da un'altra struttura, il Dividere del Divide et impera.
unfold :: (b->Forse (Tupla ab)) -> b -> [a]
Questo sembra più complicato tuttavia la funzione (b->(Tuple a b)) è responsabile della generazione degli elementi dell'elenco di output.
ad esempio, genera una lista da 10 a 1
unfold(seed -> if seed == 0 then Nothing else Just(seed,seed-1)) 10 = [10,9,8,7,6,5,4,3,2,1] generateList::Int - > [Int] generateList seed = se seed == 0 allora [] else seed:(generateList seed-1)
Uno spostamento verso FP
Dopo aver analizzato alcuni degli schemi di FP, la domanda che ti sei posto in testa all'inizio dell'articolo (ricorda). Perché ogni linguaggio, incluso JavaScript, si sta muovendo verso la programmazione funzionale? Penso che se leggi fino a questo punto capisci il fatto che le funzioni sono una potente astrazione. Sono facili da leggere e da codificare e poiché ci muoviamo verso la codifica di piccole funzioni, questo ci consente di incollarle insieme come i Lego per costruire programmi più grandi.
Scritto da Yoan Ribeiro
PS: puoi dare un'occhiata al mio discorso e al discorso di BloodyOwl (in francese). PureScript and Ragione là:
http://blog.js-republic.com/meetup-js-star-reason-purescript-programmation-fp/
