Programmation fonctionnelle en JavaScript Partie 2 - Combinateurs
Pawel Ged
Vue.js Développeur
Voici la deuxième partie de notre série d'articles consacrés à la puissance de la programmation fonctionnelle dans JavaScript. Consultez cet article pour approfondir vos connaissances sur les combinateurs.
Introduction aux combinateurs
Les combinateurs sont des fonctions de niveau supérieur qui permettent de combiner des fonctions, des variables ou d'autres combinateurs. En général, ils ne contiennent pas de déclarations de leurs propres variables ou de leur propre logique de gestion. Ils sont les seuls à permettre de rincer le contrôle dans un programme de fonctions.
Dans cet article, j'essaierai d'en couvrir quelques-uns :
Robinet
Curry
Pipe/Composition
Fourchette
Alternance
Séquence
Robinet
Un combinateur est très utile pour les fonctions qui ne renvoient rien. Il prend la fonction à laquelle le paramètre est destiné et la renvoie ensuite.
Déclaration
const tap = (fn) => (value) => {
fn(valeur) ;
retourne la valeur ;
} ;
Exemple d'impératif
const [items, setItems] = useState(() => [])
axios
.get('http://localhost')
.then({ data } => {
setItems(data)
console.log(data)
onLoadData(data)
}).then(...) // renvoie undefined - les données de la promesse ont été modifiées
Exemple déclaratif
const [items, setItems] = useState(() => [])
axios
.get('http://localhost')
.then(({ data }) => data)
.then(tap(setItems)) // (data) => { setItems(data) ; return data }
.then(tap(console.log)) // un then = une fonction = une responsabilité
.then(tap(onLoadData))
.then(...) // toujours accès aux données d'origine
// facile de maintenir le principe d'ouverture/fermeture
Curry
Il divise les arguments d'une fonction et permet de les appeler de manière séquentielle.
const sum = (a, b, c) => a + b + c
const currySum = curry(sum)
/*
appels possibles
currySum(a)(b)(c),
currySum(a)(b,c),
currySum(a,b)(c),
currySum(a,b,c)
*/
currySum(1) // (b, c) => 1 + a + b ou (b) => (c) => 1 + a + b
currySum(5)(10) // (c) => 5 + 10 + b
currySum(5, 10) // (c) => 5 + 10 + b
currySum(5)(10)(20) // 35
currySum(5, 10)(20) // 35
currySum(5)(10, 20) // 35
const divideBy = curry((a, b) => b / a)
const multiplyBy = curry((a, b) => a * b)
const divideByTwo = divideBy(2)
divideByTwo(10) // renvoie 5
const multiplyByFive = multiplyBy(5)
multiplyByFive(10) // renvoie 50
Pipe/Composition
Grâce à la composition, il est possible de passer des données d'une fonction à une autre. Il est important que les fonctions prennent le même nombre d'arguments. La différence entre pipe et compose est que le premier exécute la fonction de la première à la dernière, tandis que compose les appelle à partir de la fin.
const users = [{
uuid: '123e4567-e89b-12d3-a456-426655440000',
name : 'William'
}]
const findUser = ({ uuid : searchesUuid }) =>
users.find(({ uuid }) => uuid === searchesUuid)
const newUser = data => ({ ...data, uuid : uuid() // créer un nouvel uuid })
const findOrCreate = alt(findUser, newUser)
findOrCreate({ uuid : '123e4567-e89b-12d3-a456-426655440000' }) // renvoie l'objet William
findOrCreate({ name : 'John' }) // renvoie l'objet John avec un nouvel uuid
Séquence
Il accepte de nombreuses fonctions indépendantes et transmet le même paramètre à chacune d'entre elles. En général, ces fonctions ne renvoient aucune valeur.