SlideShare a Scribd company logo
1 of 63
Download to read offline
Comprendre la
programmation fonctionnelle
@loicknuchel
Loïc Knuchel
Geek passionné
Développeur Scala
Organisateur
Débuter avec la programmation
fonctionelle ?
High-order function
Pure function
Immutable
Functor
Currying
Monad
Applicative
Récursif
Monoid
Au fait, c’est quoi la programmation fonctionnelle ?
“La programmation fonctionnelle est un paradigme de programmation qui
considère le calcul en tant qu'évaluation de fonctions mathématiques.”
Wikipedia
“La programmation fonctionnelle est un style de programmation qui met l’accent
sur les fonctions qui ne dépendent pas de l’état du programme.”
Functionnal programming in scala
“La programmation fonctionnelle permet de coder de manière plus productive,
plus modulaire et avec moins de bugs.”
Loïc Knuchel ;)
Exemple ?
for loops are everywhere
function toUpperCase(list){
const ret = [];
for(let i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
return ret;
}
console.log(toUpperCase(['Finn', 'Rey', 'Poe']));
// ['FINN', 'REY', 'POE']
for loops are everywhere
function toUpperCase(list){
const ret = [];
for(let i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
return ret;
}
console.log(toUpperCase(['Finn', 'Rey', 'Poe']));
// ['FINN', 'REY', 'POE']
Interdiction de modifier
les paramètres !!!
for loops are everywhere
function toUpperCase(list){
const ret = [];
for(let i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
return ret;
}
console.log(toUpperCase(['Finn', 'Rey', 'Poe']));
// ['FINN', 'REY', 'POE']
Boilerplate !!!
for loops are everywhere
Array.prototype.map = function(transform){
const array = this;
const result = [];
for(let i=0; i<array.length; i++){
result[i] = transform(array[i]);
}
return result;
};
for loops are everywhere
Array.prototype.map = function(transform){
const array = this;
const result = [];
for(let i=0; i<array.length; i++){
result[i] = transform(array[i]);
}
return result;
};
Fonction d’ordre supérieur
for loops are everywhere
function toUpperCase(list){
const ret = [];
for(let i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
return ret;
}
function toUpperCase(list){
return list.map(item => item.toUpperCase());
}
Séparation technique vs métier
Array.prototype.map = function(transform){
var array = this;
var result = [];
for(var i=0; i<array.length; i++){
result[i] = transform(array[i]);
}
return result;
};
list.map(item => item.toUpperCase());
Générique / Réutilisable / Stable
Abstraction de haut niveau
Concis / Expressif / Flexible
Focalisé sur le domaine
Cas pratique
Température moyenne par localisation
const data = [
{
coords: [42.097002, -79.235326],
temperatures: [-34, 67, 101, 87]
},
{
coords: [38.888025, -121.016225],
temperatures: [-3, 4, 9, 12]
},
{
coords: [40.462512, -99.249261],
temperatures: [75, 75, 75, 75, 75]
},
...
];
// expected format :
[
// [coords, average temperature]
[[42.097002, -79.235326], 55.25],
[[38.888025, -121.016225], 5.5],
[[40.462512, -99.249261], 75],
...
]
Code impératif
function chartFormat(data){
var results = [],
totalTemp = 0,
averageTemp = 0;
for(var i=0; i < data.length; i++) {
totalTemp = 0;
for(var j=0; j < data[i].temperatures.length; j++) {
totalTemp += data[i].temperatures[j];
}
averageTemp = totalTemp / data[i].temperatures.length;
results.push([data[i].coords, averageTemp]);
}
return results;
}
● Difficile à comprendre
● Pas réutilisable / générique
● Bugs probables
● Difficile à tester
Fonctionnel
● Immutabilité
Meilleure compréhension du code
Fixe les problèmes :
● Asynchrone
● Concurrent
● Scalabilité horizontale
Fonctionnel
● Immutabilité
● Stateless Raisonnement local
Couplage réduit
Testabilité
Fonctionnel
● Immutabilité
● Stateless
● Pas d’effet de bord
Effet de bord :
● faire un appel (bdd, http, fichier…)
● récupérer la date actuelle
● accéder à une variable “globale”
● modifier un paramètre
● lancer une exception
● afficher un log
● ...
Fonctionnel
● Immutabilité
● Stateless
● Pas d’effet de bord
Raisonnement local
Couplage réduit
Composition facilitée
Testabilité
Fonctionnel
● Immutabilité
● Stateless
● Pas d’effet de bord
Functional core / Imperative shell
Fonctionnel
● Immutabilité
● Stateless
● Pas d’effet de bord
● Décomposer en fonction réutilisables
Moyenne des températures par point
Fonctionnel : moyenne des températures
function sum(numArr, currentTotal){
currentTotal = currentTotal || 0;
if(numArr.length === 0){
return currentTotal;
} else {
return sum(numArr.slice(1), currentTotal + numArr[0]);
}
}
function avg(numArr){
return sum(numArr) / numArr.length;
}
var averageTemp = avg(temperatures);
Fonctionnel : extraire les températures
var allTemperatures = data.map(function(item){
return item.temperatures;
});
const data = [
{
coords: [42.097002, -79.235326],
temperatures: [-34, 67, 101, 87]
},
{
coords: [38.888025, -121.016225],
temperatures: [-3, 4, 9, 12]
},
{
coords: [40.462512, -99.249261],
temperatures: [75, 75, 75, 75, 75]
},
...
];
Curryfication
function add1(b){
return 1+b;
}
console.log(add1(2)); // 3
function addCurry(a){
return function(b){
return a+b;
}
}
var add1 = addCurry(1);
var add2 = addCurry(2);
console.log(add1(2)); // 3
console.log(add2(2)); // 4
Fonctionnel : extraire les températures
var allTemperatures = data.map(function(item){
return item.temperatures;
});
function getAttr(attrName){
return function(item){
return item[attrName];
}
}
var allTemperatures = data.map(getAttr('temperatures'));
function mapAttr(arr, attrName){
return arr.map(getAttr(attrName));
}
Array.prototype.mapAttr = function(attrName){
return mapAttr(this, attrName);
};
var allTemperatures = data.mapAttr('temperatures');
Fonctionnel : combiner nos données
var coordsList = data.mapAttr('coords'); // [[42.097, -79.235], ...]
var avgTemps = data.mapAttr('temperatures').map(avg); // [55.25, 5.5, 75, ...]
function zip(arr1, arr2, resultArr){
resultArr = resultArr || [];
if(arr1.length === 0 || arr2.length === 0){
return resultArr;
} else {
return zip(arr1.slice(1), arr2.slice(1), resultArr.concat([arr1[0], arr2[0]]));
}
}
// zip([1, 2, 3], [‘a’, ‘b’, ‘c’]) => [[1, ‘a’], [2, ‘b’], [3, ‘c’]]
Array.prototype.zip = function(other){
return zip(this, other, []);
};
var chartData = coordsList.zip(avgTemps);
// [ [[42.097002, -79.235326], 55.25] , [[38.888025, -121.016225], 5.5], ... ]
Fonctionnel : tout combiner
function chartFormat(data){
return data.mapAttr('coords').zip(data.mapAttr('temperatures').map(avg));
}
VS
function chartFormat(data){
var results = [],
totalTemp = 0,
averageTemp = 0;
for(var i=0; i < data.length; i++) {
totalTemp = 0;
for(var j=0; j < data[i].temperatures.length; j++) {
totalTemp += data[i].temperatures[j];
}
averageTemp = totalTemp / data[i].temperatures.length;
results.push([data[i].coords, averageTemp]);
}
return results;
}
def chartFormat(data: List[((Double, Double), List[Double])]) =
data.map(_._1).zip(data.map(_._2).map(t => t.sum / t.length))
Bilan
● Plus facile à :
○ écrire
○ lire
○ maintenir
● Beaucoup moins de bugs
Scala collection API (petite partie)
def map[B](f: (A) => B): List[B]
def filter(p: (A) => Boolean): List[A]
def partition(p: (A) => Boolean): (List[A], List[A])
def zip[B](that: List[B]): List[(A, B)]
def sliding(size: Int): Iterator[List[A]]
def find(p: (A) => Boolean): Option[A]
def exists(p: (A) => Boolean): Boolean
def flatten[B]: List[B]
def flatMap[B](f: (A) => List[B]): List[B]
def groupBy[K](f: (A) => K): Map[K, List[A]]
def grouped(size: Int): Iterator[List[A]]
def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1
def reduce[A1 >: A](op: (A1, A1) => A1): A1
def forall(p: (A) => Boolean): Boolean
def take(n: Int): List[A]
def drop(n: Int): List[A]
def distinct: List[A]
Bugs are everywhere...
function toUpperCase(list){
const ret = [];
for(let i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
return ret;
}
Safe ?
Bugs are everywhere...
function toUpperCase(list){
const ret = [];
for(let i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
return ret;
}
Unsafe !
Cannot read property 'xxx'
of undefined !!!
Bugs are everywhere...
function toUpperCase(list){
const ret = [];
for(let i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
return ret;
}
function toUpperCase(list){
var ret = [];
if(Array.isArray(list)) {
for(var i=0; i<list.length; i++){
if(typeof list[i] === 'string'){
ret[i] = list[i].toUpperCase();
} else {
throw "not a string";
}
}
} else {
throw "not an array";
}
return ret;
}
Bugs are everywhere...
function toUpperCase(list){
const ret = [];
for(let i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
return ret;
}
function toUpperCase(list){
var ret = [];
if(Array.isArray(list)) {
for(var i=0; i<list.length; i++){
if(typeof list[i] === 'string'){
ret[i] = list[i].toUpperCase();
} else {
ret[i] = list[i];
}
}
}
return ret;
}
Bugs are everywhere...
function toUpperCase(list){
const ret = [];
for(let i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
return ret;
}
function toUpperCase(list){
var ret = [];
if(Array.isArray(list)) {
for(var i=0; i<list.length; i++){
if(typeof list[i] === 'string'){
ret[i] = list[i].toUpperCase();
} else {
ret[i] = list[i];
}
}
}
return ret;
}
Unreadable !
Bugs are everywhere...
function toUpperCase(list){
const ret = [];
for(let i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
return ret;
}
function toUpperCase(list){
var ret = [];
if(Array.isArray(list)) {
for(var i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
}
return ret;
}
function toUpperCase(list){
var ret = [];
if(Array.isArray(list)) {
for(var i=0; i<list.length; i++){
if(typeof list[i] === 'string'){
ret[i] = list[i].toUpperCase();
} else {
ret[i] = list[i];
}
}
}
return ret;
}
Bugs are everywhere...
function toUpperCase(list){
const ret = [];
for(let i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
return ret;
}
function toUpperCase(list){
var ret = [];
if(Array.isArray(list)) {
for(var i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
}
return ret;
}
function toUpperCase(list){
var ret = [];
if(Array.isArray(list)) {
for(var i=0; i<list.length; i++){
if(typeof list[i] === 'string'){
ret[i] = list[i].toUpperCase();
} else {
ret[i] = list[i];
}
}
}
return ret;
}
not so “smart”
Cannot read property 'xxx'
of undefined !!!
Bugs are everywhere...
function toUpperCase(list){
const ret = [];
for(let i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
return ret;
}
function toUpperCase(list){
var ret = [];
if(Array.isArray(list)) {
for(var i=0; i<list.length; i++){
ret[i] = list[i].toUpperCase();
}
}
return ret;
}
function toUpperCase(list){
var ret = [];
if(Array.isArray(list)) {
for(var i=0; i<list.length; i++){
if(typeof list[i] === 'string'){
ret[i] = list[i].toUpperCase();
} else {
ret[i] = list[i];
}
}
}
return ret;
}
Unsafe !
not so “smart”
Unreadable !
Option
Option
val myMap = Map("key" -> "value")
val v1: Option[String] = myMap.get("key") // Some("value")
val v2: Option[String] = myMap.get("miss") // None
val v3: Option[String] = v1.map(_.toUpperCase) // Some("VALUE")
val v4: Option[String] = v2.map(_.toUpperCase) // None
val v5: String = v3.getOrElse("default") // "VALUE"
val v6: String = v4.getOrElse("default") // "default"
Option
def toUpperCase(list: List[String]) =
list.map(_.toUpperCase)
def toUpperCase(list: List[Option[String]]) =
list.map(_.map(_.toUpperCase))
def toUpperCase(list: Option[List[Option[String]]]) =
list.map(_.map(_.map(_.toUpperCase)))
List.map() vs Option.map() ?
List.map() vs Option.map() ?
Fonctors !!!
def toWords(sentences: List[String]): List[List[[String]] =
sentences.map(_.split(" ").toList)
def toWords(sentences: List[String]): List[String] =
sentences.flatMap(_.split(" ").toList)
def toWords(sentences: List[String]): List[List[[String]] =
sentences.map(_.split(" ").toList)
def toWords(sentences: List[String]): List[String] =
sentences.flatMap(_.split(" ").toList)
Applicative !
def toWords(sentences: List[String]): List[List[[String]] =
sentences.map(_.split(" ").toList)
def toWords(sentences: List[String]): List[String] =
sentences.flatMap(_.split(" ").toList)
Applicative !
Fonctor + Applicative = Monad
def toWords(sentences: List[String]): List[List[[String]] =
sentences.map(_.split(" ").toList)
def toWords(sentences: List[String]): List[String] =
sentences.flatMap(_.split(" ").toList)
Future[A]
Option[A]
List[A]
Try[A]
Page[A]
Monads !!!
Level up your abstractions !
Take away
● Paramètre de fonction plutôt que donnée globale (même de classe)
● Créer des objets plutôt que de les modifier (immutable)
● Option plutôt que ‘null’
● Option / Try / Either / Validation plutôt qu’une exception
● Collection API / récursivité plutôt que boucles for/while
● Eviter les ‘if’ autant que possible
● Séparation technique / métier
● Functionnal core / Imperative shell
Références
Does the Language You Use Make a Difference ?
When DDD meets FP, good things happen
Philosohie fonctionnelle
Ur Domain Haz Monoids (vidéo)
DDD: et si on reprenait l'histoire par le bon bout ?
DDD, en vrai pour le développeur
Functional programming Illustrated by Scala
Scala School!
loicknuchel@gmail.com @loicknuchel http://loic.knuchel.org/

More Related Content

What's hot

ECMAScript 6 im Produktivbetrieb
ECMAScript 6 im ProduktivbetriebECMAScript 6 im Produktivbetrieb
ECMAScript 6 im ProduktivbetriebSebastian Springer
 
Шаблоны проектирования 2
Шаблоны проектирования 2Шаблоны проектирования 2
Шаблоны проектирования 2Constantin Kichinsky
 
C++14 reflections
C++14 reflections C++14 reflections
C++14 reflections corehard_by
 
Writeup ctf online idsecconf 2017
Writeup ctf online idsecconf 2017Writeup ctf online idsecconf 2017
Writeup ctf online idsecconf 2017idsecconf
 
โปรแกรมย่อยและฟังก์ชันมาตรฐาน
โปรแกรมย่อยและฟังก์ชันมาตรฐานโปรแกรมย่อยและฟังก์ชันมาตรฐาน
โปรแกรมย่อยและฟังก์ชันมาตรฐานknangsmiley
 
Javascrpt arale
Javascrpt araleJavascrpt arale
Javascrpt araleAlipay
 
Clang-tidy: путешествие внутрь AST C++
Clang-tidy: путешествие внутрь AST C++Clang-tidy: путешествие внутрь AST C++
Clang-tidy: путешествие внутрь AST C++corehard_by
 
Алексей Кутумов, C++ без исключений, часть 3
Алексей Кутумов,  C++ без исключений, часть 3Алексей Кутумов,  C++ без исключений, часть 3
Алексей Кутумов, C++ без исключений, часть 3Platonov Sergey
 
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговлеТененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговлеPlatonov Sergey
 
Most Common JavaScript Mistakes
Most Common JavaScript MistakesMost Common JavaScript Mistakes
Most Common JavaScript MistakesYoann Gotthilf
 
Антон Полухин. C++17
Антон Полухин. C++17Антон Полухин. C++17
Антон Полухин. C++17Sergey Platonov
 
珠三角技术沙龙新语言场 C++11
珠三角技术沙龙新语言场 C++11珠三角技术沙龙新语言场 C++11
珠三角技术沙龙新语言场 C++11翀 周
 
exercise of basic computer programming.docx
exercise of basic computer programming.docxexercise of basic computer programming.docx
exercise of basic computer programming.docxmiftah88
 
EJEMPLOS DESARROLLADOS
EJEMPLOS DESARROLLADOSEJEMPLOS DESARROLLADOS
EJEMPLOS DESARROLLADOSDarwin Durand
 
RxSwift 예제로 감잡기
RxSwift 예제로 감잡기RxSwift 예제로 감잡기
RxSwift 예제로 감잡기Yongha Yoo
 

What's hot (19)

ECMAScript 6 im Produktivbetrieb
ECMAScript 6 im ProduktivbetriebECMAScript 6 im Produktivbetrieb
ECMAScript 6 im Produktivbetrieb
 
Шаблоны проектирования 2
Шаблоны проектирования 2Шаблоны проектирования 2
Шаблоны проектирования 2
 
C++14 reflections
C++14 reflections C++14 reflections
C++14 reflections
 
Writeup ctf online idsecconf 2017
Writeup ctf online idsecconf 2017Writeup ctf online idsecconf 2017
Writeup ctf online idsecconf 2017
 
โปรแกรมย่อยและฟังก์ชันมาตรฐาน
โปรแกรมย่อยและฟังก์ชันมาตรฐานโปรแกรมย่อยและฟังก์ชันมาตรฐาน
โปรแกรมย่อยและฟังก์ชันมาตรฐาน
 
Monads
MonadsMonads
Monads
 
Javascrpt arale
Javascrpt araleJavascrpt arale
Javascrpt arale
 
All set1
All set1All set1
All set1
 
Clang-tidy: путешествие внутрь AST C++
Clang-tidy: путешествие внутрь AST C++Clang-tidy: путешествие внутрь AST C++
Clang-tidy: путешествие внутрь AST C++
 
Алексей Кутумов, C++ без исключений, часть 3
Алексей Кутумов,  C++ без исключений, часть 3Алексей Кутумов,  C++ без исключений, часть 3
Алексей Кутумов, C++ без исключений, часть 3
 
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговлеТененёв Анатолий, Boost.Asio в алгоритмической торговле
Тененёв Анатолий, Boost.Asio в алгоритмической торговле
 
Most Common JavaScript Mistakes
Most Common JavaScript MistakesMost Common JavaScript Mistakes
Most Common JavaScript Mistakes
 
Антон Полухин. C++17
Антон Полухин. C++17Антон Полухин. C++17
Антон Полухин. C++17
 
1- Sourcecode Array
1- Sourcecode Array1- Sourcecode Array
1- Sourcecode Array
 
珠三角技术沙龙新语言场 C++11
珠三角技术沙龙新语言场 C++11珠三角技术沙龙新语言场 C++11
珠三角技术沙龙新语言场 C++11
 
exercise of basic computer programming.docx
exercise of basic computer programming.docxexercise of basic computer programming.docx
exercise of basic computer programming.docx
 
デバッグ戦略
デバッグ戦略デバッグ戦略
デバッグ戦略
 
EJEMPLOS DESARROLLADOS
EJEMPLOS DESARROLLADOSEJEMPLOS DESARROLLADOS
EJEMPLOS DESARROLLADOS
 
RxSwift 예제로 감잡기
RxSwift 예제로 감잡기RxSwift 예제로 감잡기
RxSwift 예제로 감잡기
 

Viewers also liked

Programmation fonctionnelle en JavaScript
Programmation fonctionnelle en JavaScriptProgrammation fonctionnelle en JavaScript
Programmation fonctionnelle en JavaScriptLoïc Knuchel
 
задачі на відсотки
задачі на відсоткизадачі на відсотки
задачі на відсоткиViktoria Mikolaenko
 
Penerangan Program Gen-G HHHC 9201 (Kemahiran Komunikasi)
Penerangan Program Gen-G HHHC 9201 (Kemahiran Komunikasi)Penerangan Program Gen-G HHHC 9201 (Kemahiran Komunikasi)
Penerangan Program Gen-G HHHC 9201 (Kemahiran Komunikasi)FatinNorAlia
 
BJYM Campus Ambassador Program Outline
BJYM Campus Ambassador Program OutlineBJYM Campus Ambassador Program Outline
BJYM Campus Ambassador Program Outlinebjym
 
Eqpo 4 dispositivos de almacenamiento
Eqpo 4 dispositivos de almacenamientoEqpo 4 dispositivos de almacenamiento
Eqpo 4 dispositivos de almacenamientoAlfredo Hernandez
 
Presentatie spoordok 29 september
Presentatie spoordok 29 septemberPresentatie spoordok 29 september
Presentatie spoordok 29 septemberHerman Van Schie
 
Nuclear energy by_arman
Nuclear energy by_armanNuclear energy by_arman
Nuclear energy by_armanLove Hurtsz
 
Портфоліо
ПортфоліоПортфоліо
Портфоліоivferko
 
Madhyapradesh foodprocessingindustry-150706102716-lva1-app6891
Madhyapradesh foodprocessingindustry-150706102716-lva1-app6891Madhyapradesh foodprocessingindustry-150706102716-lva1-app6891
Madhyapradesh foodprocessingindustry-150706102716-lva1-app6891Jhimli Mukherjee
 
квіти – діти землі
квіти – діти земліквіти – діти землі
квіти – діти земліlarionova123
 

Viewers also liked (20)

Programmation fonctionnelle en JavaScript
Programmation fonctionnelle en JavaScriptProgrammation fonctionnelle en JavaScript
Programmation fonctionnelle en JavaScript
 
Expocion 2 equipo
Expocion 2 equipoExpocion 2 equipo
Expocion 2 equipo
 
задачі на відсотки
задачі на відсоткизадачі на відсотки
задачі на відсотки
 
Chapter 1
Chapter 1Chapter 1
Chapter 1
 
Penerangan Program Gen-G HHHC 9201 (Kemahiran Komunikasi)
Penerangan Program Gen-G HHHC 9201 (Kemahiran Komunikasi)Penerangan Program Gen-G HHHC 9201 (Kemahiran Komunikasi)
Penerangan Program Gen-G HHHC 9201 (Kemahiran Komunikasi)
 
BJYM Campus Ambassador Program Outline
BJYM Campus Ambassador Program OutlineBJYM Campus Ambassador Program Outline
BJYM Campus Ambassador Program Outline
 
Eqpo 3 partes computadora
Eqpo 3 partes computadoraEqpo 3 partes computadora
Eqpo 3 partes computadora
 
Eqpo 4 dispositivos de almacenamiento
Eqpo 4 dispositivos de almacenamientoEqpo 4 dispositivos de almacenamiento
Eqpo 4 dispositivos de almacenamiento
 
Presentatie spoordok 29 september
Presentatie spoordok 29 septemberPresentatie spoordok 29 september
Presentatie spoordok 29 september
 
BreeCS Example Report - Co2 by Contractor
BreeCS Example Report - Co2 by ContractorBreeCS Example Report - Co2 by Contractor
BreeCS Example Report - Co2 by Contractor
 
BreeCS Example Report - All Deliveries
BreeCS Example Report - All DeliveriesBreeCS Example Report - All Deliveries
BreeCS Example Report - All Deliveries
 
Pics class
Pics classPics class
Pics class
 
Who Was Philemon?
Who Was Philemon?Who Was Philemon?
Who Was Philemon?
 
Nuclear energy by_arman
Nuclear energy by_armanNuclear energy by_arman
Nuclear energy by_arman
 
Портфоліо
ПортфоліоПортфоліо
Портфоліо
 
Maths project
Maths projectMaths project
Maths project
 
Woubrugge 28 jan 2015
Woubrugge 28 jan 2015Woubrugge 28 jan 2015
Woubrugge 28 jan 2015
 
Power point per.4
Power point per.4Power point per.4
Power point per.4
 
Madhyapradesh foodprocessingindustry-150706102716-lva1-app6891
Madhyapradesh foodprocessingindustry-150706102716-lva1-app6891Madhyapradesh foodprocessingindustry-150706102716-lva1-app6891
Madhyapradesh foodprocessingindustry-150706102716-lva1-app6891
 
квіти – діти землі
квіти – діти земліквіти – діти землі
квіти – діти землі
 

More from Loïc Knuchel

Scala bad practices, scala.io 2019
Scala bad practices, scala.io 2019Scala bad practices, scala.io 2019
Scala bad practices, scala.io 2019Loïc Knuchel
 
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...Loïc Knuchel
 
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016Loïc Knuchel
 
Ionic2 - the raise of web developer, Riviera DEV le 17/06/2016
Ionic2 - the raise of web developer, Riviera DEV le 17/06/2016Ionic2 - the raise of web developer, Riviera DEV le 17/06/2016
Ionic2 - the raise of web developer, Riviera DEV le 17/06/2016Loïc Knuchel
 
FP is coming... le 19/05/2016
FP is coming... le 19/05/2016FP is coming... le 19/05/2016
FP is coming... le 19/05/2016Loïc Knuchel
 
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015Loïc Knuchel
 
Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015
Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015
Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015Loïc Knuchel
 
Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015
Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015
Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015Loïc Knuchel
 
Devoxx 2015, Atelier Ionic - 09/04/2015
Devoxx 2015, Atelier Ionic - 09/04/2015Devoxx 2015, Atelier Ionic - 09/04/2015
Devoxx 2015, Atelier Ionic - 09/04/2015Loïc Knuchel
 
Devoxx 2015, ionic chat
Devoxx 2015, ionic chatDevoxx 2015, ionic chat
Devoxx 2015, ionic chatLoïc Knuchel
 
Ionic HumanTalks - 11/03/2015
Ionic HumanTalks - 11/03/2015Ionic HumanTalks - 11/03/2015
Ionic HumanTalks - 11/03/2015Loïc Knuchel
 
Ionic bbl le 19 février 2015
Ionic bbl le 19 février 2015Ionic bbl le 19 février 2015
Ionic bbl le 19 février 2015Loïc Knuchel
 
Des maths et des recommandations - Devoxx 2014
Des maths et des recommandations - Devoxx 2014Des maths et des recommandations - Devoxx 2014
Des maths et des recommandations - Devoxx 2014Loïc Knuchel
 

More from Loïc Knuchel (13)

Scala bad practices, scala.io 2019
Scala bad practices, scala.io 2019Scala bad practices, scala.io 2019
Scala bad practices, scala.io 2019
 
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...
Mutation testing, enfin une bonne mesure de la qualité des tests ?, RivieraDe...
 
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
Ionic2, les développeurs web à l'assaut du mobile, BDX I/O le 21/10/2016
 
Ionic2 - the raise of web developer, Riviera DEV le 17/06/2016
Ionic2 - the raise of web developer, Riviera DEV le 17/06/2016Ionic2 - the raise of web developer, Riviera DEV le 17/06/2016
Ionic2 - the raise of web developer, Riviera DEV le 17/06/2016
 
FP is coming... le 19/05/2016
FP is coming... le 19/05/2016FP is coming... le 19/05/2016
FP is coming... le 19/05/2016
 
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015
Ionic Framework, L'avenir du mobile sera hybride, bdx.io le 16-10-2015
 
Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015
Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015
Ionic, ce n'est pas que de l'UI, meetup PhoneGap le 25-05-2015
 
Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015
Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015
Le développement mobile hybride sort du bois, Ch'ti JUG le 15-04-2015
 
Devoxx 2015, Atelier Ionic - 09/04/2015
Devoxx 2015, Atelier Ionic - 09/04/2015Devoxx 2015, Atelier Ionic - 09/04/2015
Devoxx 2015, Atelier Ionic - 09/04/2015
 
Devoxx 2015, ionic chat
Devoxx 2015, ionic chatDevoxx 2015, ionic chat
Devoxx 2015, ionic chat
 
Ionic HumanTalks - 11/03/2015
Ionic HumanTalks - 11/03/2015Ionic HumanTalks - 11/03/2015
Ionic HumanTalks - 11/03/2015
 
Ionic bbl le 19 février 2015
Ionic bbl le 19 février 2015Ionic bbl le 19 février 2015
Ionic bbl le 19 février 2015
 
Des maths et des recommandations - Devoxx 2014
Des maths et des recommandations - Devoxx 2014Des maths et des recommandations - Devoxx 2014
Des maths et des recommandations - Devoxx 2014
 

Comprendre la programmation fonctionnelle, Blend Web Mix le 02/11/2016

  • 2.
  • 4. Débuter avec la programmation fonctionelle ?
  • 6.
  • 7.
  • 8. Au fait, c’est quoi la programmation fonctionnelle ? “La programmation fonctionnelle est un paradigme de programmation qui considère le calcul en tant qu'évaluation de fonctions mathématiques.” Wikipedia “La programmation fonctionnelle est un style de programmation qui met l’accent sur les fonctions qui ne dépendent pas de l’état du programme.” Functionnal programming in scala “La programmation fonctionnelle permet de coder de manière plus productive, plus modulaire et avec moins de bugs.” Loïc Knuchel ;)
  • 10. for loops are everywhere function toUpperCase(list){ const ret = []; for(let i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret; } console.log(toUpperCase(['Finn', 'Rey', 'Poe'])); // ['FINN', 'REY', 'POE']
  • 11. for loops are everywhere function toUpperCase(list){ const ret = []; for(let i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret; } console.log(toUpperCase(['Finn', 'Rey', 'Poe'])); // ['FINN', 'REY', 'POE'] Interdiction de modifier les paramètres !!!
  • 12. for loops are everywhere function toUpperCase(list){ const ret = []; for(let i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret; } console.log(toUpperCase(['Finn', 'Rey', 'Poe'])); // ['FINN', 'REY', 'POE'] Boilerplate !!!
  • 13.
  • 14. for loops are everywhere Array.prototype.map = function(transform){ const array = this; const result = []; for(let i=0; i<array.length; i++){ result[i] = transform(array[i]); } return result; };
  • 15. for loops are everywhere Array.prototype.map = function(transform){ const array = this; const result = []; for(let i=0; i<array.length; i++){ result[i] = transform(array[i]); } return result; }; Fonction d’ordre supérieur
  • 16. for loops are everywhere function toUpperCase(list){ const ret = []; for(let i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret; } function toUpperCase(list){ return list.map(item => item.toUpperCase()); }
  • 17.
  • 18. Séparation technique vs métier Array.prototype.map = function(transform){ var array = this; var result = []; for(var i=0; i<array.length; i++){ result[i] = transform(array[i]); } return result; }; list.map(item => item.toUpperCase()); Générique / Réutilisable / Stable Abstraction de haut niveau Concis / Expressif / Flexible Focalisé sur le domaine
  • 20. Température moyenne par localisation const data = [ { coords: [42.097002, -79.235326], temperatures: [-34, 67, 101, 87] }, { coords: [38.888025, -121.016225], temperatures: [-3, 4, 9, 12] }, { coords: [40.462512, -99.249261], temperatures: [75, 75, 75, 75, 75] }, ... ];
  • 21. // expected format : [ // [coords, average temperature] [[42.097002, -79.235326], 55.25], [[38.888025, -121.016225], 5.5], [[40.462512, -99.249261], 75], ... ]
  • 22. Code impératif function chartFormat(data){ var results = [], totalTemp = 0, averageTemp = 0; for(var i=0; i < data.length; i++) { totalTemp = 0; for(var j=0; j < data[i].temperatures.length; j++) { totalTemp += data[i].temperatures[j]; } averageTemp = totalTemp / data[i].temperatures.length; results.push([data[i].coords, averageTemp]); } return results; } ● Difficile à comprendre ● Pas réutilisable / générique ● Bugs probables ● Difficile à tester
  • 23. Fonctionnel ● Immutabilité Meilleure compréhension du code Fixe les problèmes : ● Asynchrone ● Concurrent ● Scalabilité horizontale
  • 24. Fonctionnel ● Immutabilité ● Stateless Raisonnement local Couplage réduit Testabilité
  • 25. Fonctionnel ● Immutabilité ● Stateless ● Pas d’effet de bord Effet de bord : ● faire un appel (bdd, http, fichier…) ● récupérer la date actuelle ● accéder à une variable “globale” ● modifier un paramètre ● lancer une exception ● afficher un log ● ...
  • 26. Fonctionnel ● Immutabilité ● Stateless ● Pas d’effet de bord Raisonnement local Couplage réduit Composition facilitée Testabilité
  • 27. Fonctionnel ● Immutabilité ● Stateless ● Pas d’effet de bord Functional core / Imperative shell
  • 28. Fonctionnel ● Immutabilité ● Stateless ● Pas d’effet de bord ● Décomposer en fonction réutilisables
  • 30. Fonctionnel : moyenne des températures function sum(numArr, currentTotal){ currentTotal = currentTotal || 0; if(numArr.length === 0){ return currentTotal; } else { return sum(numArr.slice(1), currentTotal + numArr[0]); } } function avg(numArr){ return sum(numArr) / numArr.length; } var averageTemp = avg(temperatures);
  • 31. Fonctionnel : extraire les températures var allTemperatures = data.map(function(item){ return item.temperatures; }); const data = [ { coords: [42.097002, -79.235326], temperatures: [-34, 67, 101, 87] }, { coords: [38.888025, -121.016225], temperatures: [-3, 4, 9, 12] }, { coords: [40.462512, -99.249261], temperatures: [75, 75, 75, 75, 75] }, ... ];
  • 32. Curryfication function add1(b){ return 1+b; } console.log(add1(2)); // 3 function addCurry(a){ return function(b){ return a+b; } } var add1 = addCurry(1); var add2 = addCurry(2); console.log(add1(2)); // 3 console.log(add2(2)); // 4
  • 33. Fonctionnel : extraire les températures var allTemperatures = data.map(function(item){ return item.temperatures; }); function getAttr(attrName){ return function(item){ return item[attrName]; } } var allTemperatures = data.map(getAttr('temperatures')); function mapAttr(arr, attrName){ return arr.map(getAttr(attrName)); } Array.prototype.mapAttr = function(attrName){ return mapAttr(this, attrName); }; var allTemperatures = data.mapAttr('temperatures');
  • 34. Fonctionnel : combiner nos données var coordsList = data.mapAttr('coords'); // [[42.097, -79.235], ...] var avgTemps = data.mapAttr('temperatures').map(avg); // [55.25, 5.5, 75, ...] function zip(arr1, arr2, resultArr){ resultArr = resultArr || []; if(arr1.length === 0 || arr2.length === 0){ return resultArr; } else { return zip(arr1.slice(1), arr2.slice(1), resultArr.concat([arr1[0], arr2[0]])); } } // zip([1, 2, 3], [‘a’, ‘b’, ‘c’]) => [[1, ‘a’], [2, ‘b’], [3, ‘c’]] Array.prototype.zip = function(other){ return zip(this, other, []); }; var chartData = coordsList.zip(avgTemps); // [ [[42.097002, -79.235326], 55.25] , [[38.888025, -121.016225], 5.5], ... ]
  • 35. Fonctionnel : tout combiner function chartFormat(data){ return data.mapAttr('coords').zip(data.mapAttr('temperatures').map(avg)); } VS function chartFormat(data){ var results = [], totalTemp = 0, averageTemp = 0; for(var i=0; i < data.length; i++) { totalTemp = 0; for(var j=0; j < data[i].temperatures.length; j++) { totalTemp += data[i].temperatures[j]; } averageTemp = totalTemp / data[i].temperatures.length; results.push([data[i].coords, averageTemp]); } return results; } def chartFormat(data: List[((Double, Double), List[Double])]) = data.map(_._1).zip(data.map(_._2).map(t => t.sum / t.length))
  • 36.
  • 37. Bilan ● Plus facile à : ○ écrire ○ lire ○ maintenir ● Beaucoup moins de bugs
  • 38. Scala collection API (petite partie) def map[B](f: (A) => B): List[B] def filter(p: (A) => Boolean): List[A] def partition(p: (A) => Boolean): (List[A], List[A]) def zip[B](that: List[B]): List[(A, B)] def sliding(size: Int): Iterator[List[A]] def find(p: (A) => Boolean): Option[A] def exists(p: (A) => Boolean): Boolean def flatten[B]: List[B] def flatMap[B](f: (A) => List[B]): List[B] def groupBy[K](f: (A) => K): Map[K, List[A]] def grouped(size: Int): Iterator[List[A]] def fold[A1 >: A](z: A1)(op: (A1, A1) => A1): A1 def reduce[A1 >: A](op: (A1, A1) => A1): A1 def forall(p: (A) => Boolean): Boolean def take(n: Int): List[A] def drop(n: Int): List[A] def distinct: List[A]
  • 39.
  • 40. Bugs are everywhere... function toUpperCase(list){ const ret = []; for(let i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret; } Safe ?
  • 41. Bugs are everywhere... function toUpperCase(list){ const ret = []; for(let i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret; } Unsafe ! Cannot read property 'xxx' of undefined !!!
  • 42. Bugs are everywhere... function toUpperCase(list){ const ret = []; for(let i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret; } function toUpperCase(list){ var ret = []; if(Array.isArray(list)) { for(var i=0; i<list.length; i++){ if(typeof list[i] === 'string'){ ret[i] = list[i].toUpperCase(); } else { throw "not a string"; } } } else { throw "not an array"; } return ret; }
  • 43. Bugs are everywhere... function toUpperCase(list){ const ret = []; for(let i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret; } function toUpperCase(list){ var ret = []; if(Array.isArray(list)) { for(var i=0; i<list.length; i++){ if(typeof list[i] === 'string'){ ret[i] = list[i].toUpperCase(); } else { ret[i] = list[i]; } } } return ret; }
  • 44. Bugs are everywhere... function toUpperCase(list){ const ret = []; for(let i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret; } function toUpperCase(list){ var ret = []; if(Array.isArray(list)) { for(var i=0; i<list.length; i++){ if(typeof list[i] === 'string'){ ret[i] = list[i].toUpperCase(); } else { ret[i] = list[i]; } } } return ret; } Unreadable !
  • 45. Bugs are everywhere... function toUpperCase(list){ const ret = []; for(let i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret; } function toUpperCase(list){ var ret = []; if(Array.isArray(list)) { for(var i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } } return ret; } function toUpperCase(list){ var ret = []; if(Array.isArray(list)) { for(var i=0; i<list.length; i++){ if(typeof list[i] === 'string'){ ret[i] = list[i].toUpperCase(); } else { ret[i] = list[i]; } } } return ret; }
  • 46. Bugs are everywhere... function toUpperCase(list){ const ret = []; for(let i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret; } function toUpperCase(list){ var ret = []; if(Array.isArray(list)) { for(var i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } } return ret; } function toUpperCase(list){ var ret = []; if(Array.isArray(list)) { for(var i=0; i<list.length; i++){ if(typeof list[i] === 'string'){ ret[i] = list[i].toUpperCase(); } else { ret[i] = list[i]; } } } return ret; } not so “smart” Cannot read property 'xxx' of undefined !!!
  • 47. Bugs are everywhere... function toUpperCase(list){ const ret = []; for(let i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } return ret; } function toUpperCase(list){ var ret = []; if(Array.isArray(list)) { for(var i=0; i<list.length; i++){ ret[i] = list[i].toUpperCase(); } } return ret; } function toUpperCase(list){ var ret = []; if(Array.isArray(list)) { for(var i=0; i<list.length; i++){ if(typeof list[i] === 'string'){ ret[i] = list[i].toUpperCase(); } else { ret[i] = list[i]; } } } return ret; } Unsafe ! not so “smart” Unreadable !
  • 48.
  • 49.
  • 51. Option val myMap = Map("key" -> "value") val v1: Option[String] = myMap.get("key") // Some("value") val v2: Option[String] = myMap.get("miss") // None val v3: Option[String] = v1.map(_.toUpperCase) // Some("VALUE") val v4: Option[String] = v2.map(_.toUpperCase) // None val v5: String = v3.getOrElse("default") // "VALUE" val v6: String = v4.getOrElse("default") // "default"
  • 52. Option def toUpperCase(list: List[String]) = list.map(_.toUpperCase) def toUpperCase(list: List[Option[String]]) = list.map(_.map(_.toUpperCase)) def toUpperCase(list: Option[List[Option[String]]]) = list.map(_.map(_.map(_.toUpperCase)))
  • 54. List.map() vs Option.map() ? Fonctors !!!
  • 55. def toWords(sentences: List[String]): List[List[[String]] = sentences.map(_.split(" ").toList) def toWords(sentences: List[String]): List[String] = sentences.flatMap(_.split(" ").toList)
  • 56. def toWords(sentences: List[String]): List[List[[String]] = sentences.map(_.split(" ").toList) def toWords(sentences: List[String]): List[String] = sentences.flatMap(_.split(" ").toList) Applicative !
  • 57. def toWords(sentences: List[String]): List[List[[String]] = sentences.map(_.split(" ").toList) def toWords(sentences: List[String]): List[String] = sentences.flatMap(_.split(" ").toList) Applicative ! Fonctor + Applicative = Monad
  • 58. def toWords(sentences: List[String]): List[List[[String]] = sentences.map(_.split(" ").toList) def toWords(sentences: List[String]): List[String] = sentences.flatMap(_.split(" ").toList) Future[A] Option[A] List[A] Try[A] Page[A] Monads !!!
  • 59. Level up your abstractions !
  • 60. Take away ● Paramètre de fonction plutôt que donnée globale (même de classe) ● Créer des objets plutôt que de les modifier (immutable) ● Option plutôt que ‘null’ ● Option / Try / Either / Validation plutôt qu’une exception ● Collection API / récursivité plutôt que boucles for/while ● Eviter les ‘if’ autant que possible ● Séparation technique / métier ● Functionnal core / Imperative shell
  • 61.
  • 62. Références Does the Language You Use Make a Difference ? When DDD meets FP, good things happen Philosohie fonctionnelle Ur Domain Haz Monoids (vidéo) DDD: et si on reprenait l'histoire par le bon bout ? DDD, en vrai pour le développeur Functional programming Illustrated by Scala Scala School!