Newsgroup: it.comp.lang.javascript
Titolo: programmazione funzionale

Programmo per puro diletto, non per professione, in JS.
Ho appena finito di leggere degli articoli sulla programmazione 
funzionale (si dice così?) ma non ci ho capito molto.
Ho capito cosa sono le funzioni pure, anche se non so bene come 
implementarle nei miei programmi (rimanderò le mie domande se trovo 
qualcuno che ne capisce).
Ma cosa si intende per changing-state and mutable data che andrebbero 
evitati come la peste?
 
 

 evitati come la peste?
 
Significa che quando hai una variabile con un certo valore, non dovresti
più cambiarlo. Di fatto programmi solo con costanti.
 
Non sempre è fattibile, o efficiente, ma aiuta a evitare parecchi
problemi, soprattutto quando fai programmazione concorrente (multithread
o asincrona).
 
Se usi ES6 e transpili, puoi usare `const` al posto di `var` o `let`,
anche se non è proprio costante del tutto. :D
 
Per esempio, diciamo che hai un array:
 
const a = [1, 2]
 
Se devi aggiungere un terzo elemento, non lo aggiungi all'array con
push, ma copi tutto l'array in un nuovo array e aggiungi il terzo
elemento alla fine:
 
const b = [...a, 3]
 
In questo modo, se stai usando a in una callback che verrà eseguita alla
fine di una promise, per esempio, sei sicuro che conterrà sempre e solo
2 valori (1 e 2) indipendentemente da quanto tempo dopo la callback
viene chiamata.
 
È un concetto fondamentale in FP perché, assieme alle funzioni pure,
permette di parallelizzare qualsiasi cosa.
 
Per esempio:
 
const a = ['http://...', 'https://...', ...] // (1000 URL)
const options = Object.freeze({
  cache: 'no-cache',
  headers: {'Content-type':'application/json'},
})
 
const res = a.map(url => fetch(url, options))
 
Stai potenzialmente lanciando 1000 thread (o meglio: funzioni
asincrone), ma non sai quando verranno lanciate, o quando finiranno.
 
Se qualcosa modifica la variabile options mentre il motore sta ancora
lanciando queste fetch, potresti trovarti una parte (indeterminata)
delle funzioni che passano valori sbagliati.
 
Rendendo options immutabile (non basta const, per questo uso anche
Object.freeze) garantisci che non possa succedere.
 
Una cosa che ancora manca nella "cultura" dello sviluppatore JS medio è
il concetto di Monad, anche se una Promise in realtà lo è (più o meno :D).
 
È un concetto utile quando hai side-effects, e infatti fetch lo usa
appunto per gestire il side-effect di connettersi a un canale di I/O,
così come le funzioni di accesso asincrono ai file.
 
Spero di non aver creato più confusione di prima. :D
 
Bye.

 Spero di non aver creato più confusione di prima. :D
 
No, anzi, ti ringrazio del tempo che mi hai dedicato.
 
Però c'è qualcosa che ancora non capisco.
 
Ho imparato (spero) a sostituire i miei cicli for... con i metodi .map, 
.reduce e .filter per passare dall'approccio imperativo a quello 
dichiarativo.
 
Ma non riesco a scrivere il mio codice assemblando delle funzioni pure.
Per esempio, in questo articolo
https://medium.com/the-renaissance-developer/concepts-of-functional-programming-in-javascript-6bc84220d2aa
 
si dice che le funzioni pure non dovrebbero usare oggetti globali.
 
Ebbene, io non ci riesco. Scrivo programmini di animazione usando la 
libreria D3, che più o meno sono formulati così:
 
var svg=d3.append("svg")...
 
var obj1=svg.append(...
 
var obj2=svg.append(...
 
function animaObj1() {
	obj1
	.transition()
	...
	.on("end",function() {
	// qualche altra funzione (*)
	}
	// (*) 	immagino che .on("end",...)
	// sia una qualche forma di premise
}
 
function animaObj2() {
	obj2
	.transition()
	...
	.on("end",function() {
	// qualche altra funzione
	}
}
 
// altre funzioni che definiscono delle transizioni
 
function ...
 
// e per finire (semplificando al massimo il discorso)
 
function main() {
	...
	animaobj1()
	...
	animaobj2()
}
 
main()
 
Cioè: dichiaro alcuni (pochi) oggetti globali che poi sono accessibili a 
tutte le funzioni. Tutto è strutturato affinché queste funzioni siano in 
grado di accedere agli oggetti obj1 e obj2, a loro volta definiti dentro 
l'oggetto svg.
 
Potrei dichiarare tali oggetti parametri delle funzioni che li usano, così:
 
function animaObj1(shape) {
	shape
	.transition()
	...
	.on("end",function() {
	// qualche altra funzione
	}
}
 
ma queste funzioni *modificano* tali oggetti, quindi violerei il 
principio di immutabilità... e d'altronde il programma deve modificare 
gli oggetti obj1 e obj2, per mostrare i cambiamenti dei corrispondenti 
elementi dom a video...
 
Sono riuscito a spiegare la mia difficoltà?

 libreria D3, che più o meno sono formulati così:
 
Premetto che non conosco quasi per niente D3.js, ma se è pensato per
lavorare con oggetti mutabili, sarà abbastanza difficile adattarlo a
funzioni pure.
 
In particolare per UI in generale (e per i giochi in particolare) si sta
affermando più il "paradigma" ECS che non la programmazione funzionale pura.
 
Per D3, probabilmente uno dei modi potrebbe essere di avere una lista
degli oggetti originali, e passarli uno per uno (via map()) alle
funzioni che prendono i valori dell'oggetto originale e creano nuovi
oggetti con i valori leggermente modificati, e alla fine ricreare da
zero l'oggetto svg e mapparlo sul DOM.
 
Probabilmente ammazzerà le prestazioni e introdurrà glitch di animazione. :)
 
Ho trovato questo:
https://skillsmatter.com/skillscasts/7342-immutable-js-d3-js
 
 
che sembra spiegare come integrare d3 con immutable.js e react, ma non
conoscendo d3 non ci capisco tantissimo.
 
Secondo me la tua soluzione di modificare gli oggetti uno per uno non è
male. Sì, violi l'immutabilità, ma perché D3 richiede che gli oggetti
siano mutabili.
 
Bye.