Kevin Olivier Avignon: Une introduction à la pensée fonctionnelle avec F#

Post on 15-Jan-2017

390 views 2 download

Transcript of Kevin Olivier Avignon: Une introduction à la pensée fonctionnelle avec F#

Une introduction à la pensée fonctionnelle avec F#Kevin Avignon

AVANT DE COMMENCER LA PRÉSENTATION

Qui suis-je ?◦ Étudiant en génie des technologies de l’information (ÉTS)

◦ Stagiaire C# & F# en systèmes distribués chez Genetec

Contenu de la présentation1. Qu’est-ce que le paradigme fonctionnel ?2. Pourquoi s’intéresser à F# ?3. Les rudiments de F#4. Éléments clés de la pensée fonctionnelle5. Domaines d’application pour F#

1.Qu’est-ce que le paradigme fonctionnel?

Qu’est-ce qu’un paradigme de programmation ?

Style de programmation permettant de solutionner un problème informatique à

l'aide d'un langage (ex: C#, F#, VB.NET)

Exemples de paradigmes connus:

Procédurale (routine): Une série d’étapes à réaliser

Orienté-objet : Une collection d’objets en perpetuelle intéraction

Paradigme fonctionnelUne suite de fonctions mathématiques sans états

Une fonction mathématique est

Une expression (un algorithme avec ses entrées/sorties)

Générale

Sujet à réduction jusqu’à être irréductible

Les fonctions mathématiques n’admettent pas

Un changement d’état

La mutation des données

Pourquoi s’y intéresser?Le code est plus simple à gérer (aucun état)

Une gestion de la concurrence sans soucis

Les programmes sont généralement plus courts

2. Pourquoi s’intéresser à F#

General Purpose Language

F# est un langage de .NET, tout comme C# et VB.NET

Il est en mesure de répondre à une variété de problèmes en tout genre

S’intégre dans une solution .NET existante

Peut être exploité pour écrire de l’orienté-objet, impératif, fonctionnel ou autre

Des solutions simples pour des problèmes complexes

F# est concis et très expressif.

Moins de code nécessaire à lire et maintenir

Les fonctions de haut niveau encourage la réutilisabilité

FSIOutil permettant d’exécuter le code F# sans passer par debug

C’est un interpreteur à l’intérieur d’un command prompt

Permet également d’écrire du code pendant l’exécution

Pour être utiliser avec Visual Studio

Ctrl+Alt+F

Clique droit + Option Execute in Interactive

Chaque instruction doit être compléter avec “;;” au lieu d’un dans FSI

Justesse du code

Les valeurs(pas de variables) sont immuables par défaut

Immuabilité : L’état de la valeur ne peut être modifié après son attribution

Un système de type de données stricte

Autant votre pire ennemi que votre meilleur ami

Du pattern matching très flexible et exhaustif

Pattern matchingDéfinition : Une solution flexible pour modifier les données selon des règles spécifiques (patterns)

Permet de naviguer et décomposer simplement dans une structure de données

Chaque pattern est examiné pour valider si c’est compatible avec la structure de donnéestype LeavesColor= | Red = 0 | Green = 1

let printColorName (color:LeavesColor) = match color with | Color.Red -> printfn "Red" | Color.Green -> printfn "Green" | _ -> ()printColorName LeavesColor.RedprintColorName LeavesColor.Green

Aucun NullReferenceExceptionOption type

Type polymorphique encapsulant une valeur optionnelle

S’il y a une valeur à retourner -> Some<T>

Sinon -> None

N’est jamais à l’état null

Semblable aux nullableslet compute = function | None -> "No value" | Some x -> sprintf "The value is: %d" x

printfn "%s" ( Some 42 |> compute)(* The value is: 42 *)printfn "%s" (compute None) (* No value *)

Type inference par défautAvec C#, c’est fait en ayant recours au keyword var afin d’augmenter la lisibilité

Dictionary<List<SomeObject>,string[]> maVariable = new

Dictionary<List<SomeObject>,string[]>();

var maSecondeVariable = new Dictionary<List<SomeObject>,string[]>();

Le compilateur est intelligent et déduit rapidement le type exact d’une valeurL’information est déduite selon le contexteS’il manque d’information, il faut lui en donner davantage sinon la solution ne

“build” pas

let f a b = a + b + 100 //Retourne une valeur de type uint32 (int)

Moins de bugsSystème de type strict

Utiliser des Option types

Type inference

Immuabilité

Unit of Measures (custom unit)

[<Measure>] type foot

let distance = 3.0<foot>

// type inference for result

let distance2 = distance * 2.0

// type inference for input and output

let addThreeFeet ft = ft + 3.0<foot>

3. Les rudiments en F#

let bindingsKeyword très puissant permet de :

Faire du value binding ou attribuer une valeur à un symbol (nom de variable)

Déclarer une fonction

Déclarer une valeur locale/globale

Déclarer une valeur mutable

Control flow - les ifC’est une structure if-then-elseCe sont des expressions avec des branches de types équivalentesMieux vaut utiliser le pattern matching que if dans certains cas

// bad

let badF x =

if x = 1

then "a" else "b"

// best

let bestF x =

match x with

| 1 -> "a"

| _ -> "b"

Control flow - Les boucles

Comme la structure conditionnelle if, les boucles conservent une structure familière

Il s’agit malgré tout d’expressions

Les boucles retournent le type unit

S’apparent à void

C’est une absence de valeur représenté par ()

Les do binding demeurent locaux

Retournent également unit

Aucun équivalent de break ou continue

Control flow - for loopLa boucle for a la structure suivante :

for start - to | downto - do body-expression

Exemple: let f = for i in [1..10] do i + i |> ignore let newF = for i=10 downto 1 do i + i |> ignore

Control flow - foreachLa boucle foreach a la structure suivante :

for pattern in enumerable-expression dobody-expression

// Looping over a list.let list1 = [ 1; 5; 100; 450; 788 ]for i in list1 do printfn "%d" i

Control flow - while loopLa boucle while a la structure suivante :

while test expression dobody-expression

let lookForValue value maxValue = let mutable continueLooping = true let randomNumberGenerator = new Random() while continueLooping do // Generate a random number between 1 and maxValue. let rand = randomNumberGenerator.Next(maxValue) printf "%d " rand if rand = value then printfn "\nFound a %d!" value continueLooping <- false

Pipeline OperatorsPipe-forward operator ( |> )

Permet de passer une valeur intermédiaire à une fonction

Définit comme let (|>) f x = f x

[1..2..40] List.filter (fun value -> value %2 =0) |> printfn

Foward composition operator ( >> )Permet de composer la fonction f dans la fonction g

Se définit comme let ( >> ) f g x = g (f x )

Pipe-backward operator ( <| ) L’inverse du |>

Backward composition operator ( << )L’inverse du >>

Array, List & SeqIl s’agit des Collection types les plus importants et utilisés en F#

Array est une mutable collection ayant une taille fixe avec un 0 based index

let array1 = [| 1; 2; 3 |]

List est une collection immuable d’éléments ordonnés du même type

let list123 = [ 1; 2; 3 ]

Seq ou Sequence, est un équivalent à IEnumerable<T>

Tous les structures .NET dérivant de IEnumerable peuvent être des Seq

Il est possible de passer de l’un à l’autre en faisantCollectionType.toArray|toList|ToSeq

Tuples

Un regroupement de données pouvant être de type différent

(1,2) // Tuple de int, int

(1, “one”) Tuple de int, string

(1, 2.0, “three”, 3+1) //Tuple de int, float, string, expression

Donne une solution pour retourner plusieurs valeurs dans une fonction

Discriminated UnionsPermettent de rapidement prototyper un domaine d’affaires

Un ensemble de types hétérogènes

Les bons types de données

Les types non valides

Exemple :

type FormeGeometrique =

| Rectangle of longeur : int * largeur:int

|Cercle of int

RecordsSont immuables par défaut

Le record peut être mise à jour en faisant une copie et modifiant un champ spécifique

Se différencient des classe en orienté-objetSont seulement des propriété exposées

N’ont aucun constructeur

type Point3D = { x: float; y: float; z: float }let evaluatePoint (point: Point3D) = match point with | { x = 0.0; y = 0.0; z = 0.0 } -> printfn "Point is at the origin." | { x = xVal; y = 0.0; z = 0.0 } -> printfn "Point is on the x-axis. Value is %f." xVal | { x = 0.0; y = yVal; z = 0.0 } -> printfn "Point is on the y-axis. Value is %f." yVal | { x = 0.0; y = 0.0; z = zVal } -> printfn "Point is on the z-axis. Value is %f." zVal | { x = xVal; y = yVal; z = zVal } -> printfn "Point is at (%f, %f, %f)." xVal yVal zVal

Modules

Un regroupement logique du code tout comme un namespace

Un fichier est mis par défaut dans un module si rien n’est spécifié

S’apparente à une classe statique

4. Éléments clés de la pensée fonctionnelle

Les fonction sont les first citizens

C’est le paradigme fonctionnel, il est normal de prioriser les fonctions

Il faut voir une fonction comme étant un objet mathématique

Système dynamique et souple

Il est possible de passer une fonction comme un input

Il est possible de retourner une fonction comme output

Préserver les états orignauxEn manipulant un Collection type (list)

Penser à conserver son état original

C’est une entité à manipuler avec soin

Copier l’entité au besoin

Renforcer l’immuabilité dans vos programmes

Moins de bugs

Parallélisation et concurrence plus simple

Éviter la mutabilitéPermet d’éviter les side-effects

Les valeurs ne sont pas modifier après leur évaluaion

Rend le code thread-safe

S’assure qu’un thread ne peut modifier la valeur pendant son cycle

Pour mettre à jour une donnée

Il suffit simplement d’en faire la copie et utiliser cette copie

Retourner des fonctions non encapsulées

S’agit d’un calcul simple parfois

Exploiter la récursionLa fonction s’appelle elle-même jusqu’à temps de compléter son

itération

Augmente la lisibilité pour le programmeur

Réduit le code

Engendre théoriquement moins de bugs

Partial function applicationTechnique puissante

Ne pas avoir à complètement appliquer une fonction

Permet de définir une fonction à N paramètre

Obtenir le résultat final au moment voululet add42 = (+) 42 // partial application

add42 1

add42 3

S’éloigner de la mentalité OOCesser de penser en classe et exploiter

Records

Discriminated Unions

Cesser de penser aux méthodes à encapsuler

Créer des high order functions

L’héritage n’a plus sa place ici

Penser plutôt au partial function application

Pouvoir passer des fonctions en tant que paramètres

Pattern matching > if structurePermet de valider tous les cas possibles

Le compilateur mentionne si une situation a été oublié

Rend les cas à traiter plus simples à comprendre

Structure avec moins de “bruit”

5. Domaines d’application pour F#

Domaines d’applications 1.L’apprentissage machine

2.L’analyse de données

3.L’actuariat

4.Le développement web (WebSharper)

5.Le développement mobile (Xamarin)

6.Le traitement vidéo avec le GPU

7.Cloud computing

Période de questions

Réference intéressantes1.LIU,Tao. F# for C# Developers.2013 (Livre)

2.PETRICEK,Tomas,TRELFORD,Phillip. F# Deep dives.2015 (Livre)

3.http://fsharpforfunandprofit.com/learning-fsharp/

4.https://msdn.microsoft.com/en-us/library/hh967652.aspx

5.http://www.codeproject.com/Articles/462767/How-to-Think-Like-a-Functional-Programmer

6.http://fsharpconf.com/ (Conference F# en ligne le 4 mars 2016)

7.https://github.com/Kavignon/MSDEVMTL_SampleCode

8.https://github.com/ChrisMarinos/FSharpKoans