diff options
Diffstat (limited to 'fr-fr/fsharp-fr.html.markdown')
-rw-r--r-- | fr-fr/fsharp-fr.html.markdown | 631 |
1 files changed, 631 insertions, 0 deletions
diff --git a/fr-fr/fsharp-fr.html.markdown b/fr-fr/fsharp-fr.html.markdown new file mode 100644 index 00000000..3fd41676 --- /dev/null +++ b/fr-fr/fsharp-fr.html.markdown @@ -0,0 +1,631 @@ +--- +language: F# +lang: fr-fr +contributors: + - ["Scott Wlaschin", "http://fsharpforfunandprofit.com/"] +translators: + - ["Alois de Gouvello", "https://github.com/aloisdg"] +filename: learnfsharp-fr.fs +--- + +F# est un langage de programmation fonctionnel et orienté objet. Il est gratuit et son code source est ouvert. Il tourne sur Linux, Mac, Windows et plus. + +Il possède un puissant système de type qui piège de nombreuses erreurs à la compilation, mais il utilise l'inférence de type ce qui lui permet d'être lu comme un langage dynamique. + +La syntaxe de F# est différente des langages héritant de C. + +* Les accolades ne sont pas utilisées pour délimiter les blocs de code. À la place, l'indentation est utilisée (à la manière de Python). +* Les espaces sont utilisés pour séparer les paramètres à la place des virgules. + +Si vous voulez essayer le code ci-dessous, vous pouvez vous rendre sur [tryfsharp.org](http://www.tryfsharp.org/Create) et le coller dans le [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop). + +```fsharp + +// Les commentaires d'une seule ligne commencent par un double slash +(* Les commentaires multilignes utilise les paires (* . . . *) + +-fin du commentaire multilignes- *) + +// ================================================ +// Syntaxe de base +// ================================================ + +// ------ "Variables" (mais pas vraiment) ------ +// Le mot clé "let" définit une valeur (immutable) +let myInt = 5 +let myFloat = 3.14 +let myString = "hello" // Notons qu'aucun type n'est nécessaire + +// ------ Listes ------ +let twoToFive = [2;3;4;5] // Les crochets créent une liste avec + // des point-virgules pour délimiteurs. +let oneToFive = 1 :: twoToFive // :: crée une liste avec un nouvel élément +// Le résultat est [1;2;3;4;5] +let zeroToFive = [0;1] @ twoToFive // @ concatène deux listes + +// IMPORTANT: les virgules ne sont jamais utilisées pour délimiter, +// seulement les point-virgules ! + +// ------ Fonctions ------ +// Le mot clé "let" définit aussi le nom d'une fonction. +let square x = x * x // Notons qu'aucune parenthèse n'est utilisée. +square 3 // Maitenant, exécutons la fonction. + // Encore une fois, aucune parenthèse. + +let add x y = x + y // N'utilisez pas add (x,y) ! Cela signifie + // quelque chose de complètement différent. +add 2 3 // À présent, exécutons la fonction. + +// Pour définir une fonction sur plusieurs lignes, utilisons l'indentation. +// Les point-virgules ne sont pas nécessaires. +let evens list = + let isEven x = x%2 = 0 // Définit "isEven" comme une fonction imbriquée + List.filter isEven list // List.filter est une fonction de la librairie + // à deux paramètres: un fonction retournant un + // booléen et une liste sur laquelle travailler + +evens oneToFive // À présent, exécutons la fonction. + +// Vous pouvez utilisez les parenthèses pour clarifier. +// Dans cet exemple, "map" est exécutée en première, avec deux arguments, +// ensuite "sum" est exécutée sur le résultat. +// Sans les parenthèses, "List.map" serait passé en argument à List.sum. +let sumOfSquaresTo100 = + List.sum ( List.map square [1..100] ) + +// Vous pouvez rediriger la sortie d'une fonction vers une autre avec "|>" +// Rediriger des données est très commun en F#, comme avec les pipes UNIX. + +// Voici la même fonction sumOfSquares écrite en utilisant des pipes +let sumOfSquaresTo100piped = + [1..100] |> List.map square |> List.sum // "square" est déclaré avant + +// Vous pouvez définir des lambdas (fonctions anonymes) grâce au mot clé "fun" +let sumOfSquaresTo100withFun = + [1..100] |> List.map (fun x -> x*x) |> List.sum + +// En F#, il n'y a pas de mot clé "return". Une fonction retourne toujours +// la valeur de la dernière expression utilisée. + +// ------ Pattern Matching ------ +// Match..with.. est une surcharge de la condition case/switch. +let simplePatternMatch = + let x = "a" + match x with + | "a" -> printfn "x is a" + | "b" -> printfn "x is b" + | _ -> printfn "x is something else" // underscore correspond à tout le reste + +// F# n'autorise pas la valeur null par défaut -- vous devez utiliser le type Option +// et ensuite faire correspondre le pattern. +// Some(..) et None sont approximativement analogue à des wrappers de Nullable +let validValue = Some(99) +let invalidValue = None + +// Dans cet exemple, match..with trouve une correspondance à "Some" et à "None", +// et affiche la valeur du "Some" en même temps. +let optionPatternMatch input = + match input with + | Some i -> printfn "input is an int=%d" i + | None -> printfn "input is missing" + +optionPatternMatch validValue +optionPatternMatch invalidValue + +// ------ Affichage ------ +// Les fonctions printf/printfn sont similaires aux fonctions +// Console.Write/WriteLine de C#. +printfn "Printing an int %i, a float %f, a bool %b" 1 2.0 true +printfn "A string %s, and something generic %A" "hello" [1;2;3;4] + +// Il y a aussi les fonctions printf/sprintfn pour formater des données +// en string. C'est similaire au String.Format de C#. + +// ================================================ +// Plus sur les fonctions +// ================================================ + +// F# est un véritable langage fonctionel -- les fonctions sont des +// entités de premier ordre et peuvent êtres combinées facilement +// pour créer des constructions puissantes + +// Les modules sont utilisés pour grouper des fonctions ensemble. +// L'indentation est nécessaire pour chaque module imbriqué. +module FunctionExamples = + + // définit un simple fonction d'addition + let add x y = x + y + + // usage basique d'une fonction + let a = add 1 2 + printfn "1+2 = %i" a + + // partial application to "bake in" parameters (?) + let add42 = add 42 + let b = add42 1 + printfn "42+1 = %i" b + + // composition pour combiner des fonctions + let add1 = add 1 + let add2 = add 2 + let add3 = add1 >> add2 + let c = add3 7 + printfn "3+7 = %i" c + + // fonctions de premier ordre + [1..10] |> List.map add3 |> printfn "new list is %A" + + // listes de fonction et plus + let add6 = [add1; add2; add3] |> List.reduce (>>) + let d = add6 7 + printfn "1+2+3+7 = %i" d + +// ================================================ +// Listes et collections +// ================================================ + +// Il y a trois types de collection ordonnée : +// * Les listes sont les collections immutables les plus basiques +// * Les tableaux sont mutables et plus efficients +// * Les séquences sont lazy et infinies (e.g. un enumerator) +// +// Des autres collections incluent des maps immutables et des sets +// plus toutes les collections de .NET + +module ListExamples = + + // les listes utilisent des crochets + let list1 = ["a";"b"] + let list2 = "c" :: list1 // :: pour un ajout au début + let list3 = list1 @ list2 // @ pour la concatenation + + // Compréhensions des listes (aka générateurs) + let squares = [for i in 1..10 do yield i*i] + + // Générateur de nombre premier + let rec sieve = function + | (p::xs) -> p :: sieve [ for x in xs do if x % p > 0 then yield x ] + | [] -> [] + let primes = sieve [2..50] + printfn "%A" primes + + // le pattern matching pour les listes + let listMatcher aList = + match aList with + | [] -> printfn "the list is empty" + | [first] -> printfn "the list has one element %A " first + | [first; second] -> printfn "list is %A and %A" first second + | _ -> printfn "the list has more than two elements" + + listMatcher [1;2;3;4] + listMatcher [1;2] + listMatcher [1] + listMatcher [] + + // Récursion en utilisant les listes + let rec sum aList = + match aList with + | [] -> 0 + | x::xs -> x + sum xs + sum [1..10] + + // ----------------------------------------- + // Fonctions de la librairie standard + // ----------------------------------------- + + // map + let add3 x = x + 3 + [1..10] |> List.map add3 + + // filtre + let even x = x % 2 = 0 + [1..10] |> List.filter even + + // beaucoup plus -- se référer à la documentation + +module ArrayExamples = + + // les tableaux utilisent les crochets avec des barres + let array1 = [| "a";"b" |] + let first = array1.[0] // accès à l'index en utilisant un point + + // le pattern matching des tableaux est le même que celui des listes + let arrayMatcher aList = + match aList with + | [| |] -> printfn "the array is empty" + | [| first |] -> printfn "the array has one element %A " first + | [| first; second |] -> printfn "array is %A and %A" first second + | _ -> printfn "the array has more than two elements" + + arrayMatcher [| 1;2;3;4 |] + + // Fonctions de la librairie standard comme celles des listes + [| 1..10 |] + |> Array.map (fun i -> i+3) + |> Array.filter (fun i -> i%2 = 0) + |> Array.iter (printfn "value is %i. ") + +module SequenceExamples = + + // Les séquences utilisent des accolades + let seq1 = seq { yield "a"; yield "b" } + + // Les séquences peuvent utiliser yield et + // peuvent contenir des sous-sequences + let strange = seq { + // "yield" ajoute un élément + yield 1; yield 2; + + // "yield!" ajoute une sous-sequence complète + yield! [5..10] + yield! seq { + for i in 1..10 do + if i%2 = 0 then yield i }} + // test + strange |> Seq.toList + + // Les séquences peuvent être créées en utilisant "unfold" + // Voici la suite de fibonacci + let fib = Seq.unfold (fun (fst,snd) -> + Some(fst + snd, (snd, fst + snd))) (0,1) + + // test + let fib10 = fib |> Seq.take 10 |> Seq.toList + printf "first 10 fibs are %A" fib10 + +// ================================================ +// Types de données +// ================================================ + +module DataTypeExamples = + + // Toutes les données sont immutables par défaut + + // Les tuples sont de simple et rapide types anonymes + // -- Utilisons une virgule pour créer un tuple + let twoTuple = 1,2 + let threeTuple = "a",2,true + + // Pattern match pour déballer + let x,y = twoTuple // assigne x=1 y=2 + + // ------------------------------------ + // Record types ont des champs nommés + // ------------------------------------ + + // On utilise "type" avec des accolades pour définir un type record + type Person = {First:string; Last:string} + + // On utilise "let" avec des accolades pour créer un record (enregistrement) + let person1 = {First="John"; Last="Doe"} + + // Pattern match pour déballer + let {First=first} = person1 // assigne first="john" + + // ------------------------------------ + // Union types (ou variants) ont un set (ensemble) de choix + // Un seul cas peut être valide à la fois. + // ------------------------------------ + + // On utilise "type" avec bar/pipe pour definir un union type + type Temp = + | DegreesC of float + | DegreesF of float + + // On utilise un de ces choix pour en créér un + let temp1 = DegreesF 98.6 + let temp2 = DegreesC 37.0 + + // Pattern match on all cases to unpack(?) + let printTemp = function + | DegreesC t -> printfn "%f degC" t + | DegreesF t -> printfn "%f degF" t + + printTemp temp1 + printTemp temp2 + + // ------------------------------------ + // Types récursif + // ------------------------------------ + + // Les types peuvent être combinés récursivement de façon complexe + // sans avoir à créer des sous-classes + type Employee = + | Worker of Person + | Manager of Employee list + + let jdoe = {First="John";Last="Doe"} + let worker = Worker jdoe + + // ------------------------------------ + // Modelling with types(?) + // ------------------------------------ + + // Les types union sont excellents pour modelling state without using flags(?) + type EmailAddress = + | ValidEmailAddress of string + | InvalidEmailAddress of string + + let trySendEmail email = + match email with // utilisations du pattern matching + | ValidEmailAddress address -> () // envoyer + | InvalidEmailAddress address -> () // ne pas envoyer + + // Combiner ensemble, les types union et les types record + // offrent une excellente fondation pour le domain driven design. + // Vous pouvez créer des centaines de petit types qui reflèteront fidèlement + // le domain. + + type CartItem = { ProductCode: string; Qty: int } + type Payment = Payment of float + type ActiveCartData = { UnpaidItems: CartItem list } + type PaidCartData = { PaidItems: CartItem list; Payment: Payment} + + type ShoppingCart = + | EmptyCart // aucune donnée + | ActiveCart of ActiveCartData + | PaidCart of PaidCartData + + // ------------------------------------ + // Comportement natif des types + // ------------------------------------ + + // Les types natifs ont un comportement "prêt-à-l'emploi" des plus utiles, sans code à ajouter. + // * Immutabilité + // * Pretty printing au debug + // * Egalité et comparaison + // * Sérialisation + + // Le Pretty printing s'utilise avec %A + printfn "twoTuple=%A,\nPerson=%A,\nTemp=%A,\nEmployee=%A" + twoTuple person1 temp1 worker + + // L'égalité et la comparaison sont innés + // Voici un exemple avec des cartes. + type Suit = Club | Diamond | Spade | Heart + type Rank = Two | Three | Four | Five | Six | Seven | Eight + | Nine | Ten | Jack | Queen | King | Ace + + let hand = [ Club,Ace; Heart,Three; Heart,Ace; + Spade,Jack; Diamond,Two; Diamond,Ace ] + + // tri + List.sort hand |> printfn "sorted hand is (low to high) %A" + List.max hand |> printfn "high card is %A" + List.min hand |> printfn "low card is %A" + +// ================================================ +// Les Active patterns +// ================================================ + +module ActivePatternExamples = + + // F# a un type particulier de pattern matching nommé "active patterns" + // où le pattern peut être parsé ou détecté dynamiquement. + + // "banana clips" est la syntaxe pour l'active patterns + + // par exemple, on définit un "active" pattern pour correspondre à des types "character"... + let (|Digit|Letter|Whitespace|Other|) ch = + if System.Char.IsDigit(ch) then Digit + else if System.Char.IsLetter(ch) then Letter + else if System.Char.IsWhiteSpace(ch) then Whitespace + else Other + + // ... et ensuite on l'utilise pour rendre la logique de parsing plus claire + let printChar ch = + match ch with + | Digit -> printfn "%c is a Digit" ch + | Letter -> printfn "%c is a Letter" ch + | Whitespace -> printfn "%c is a Whitespace" ch + | _ -> printfn "%c is something else" ch + + // afficher une liste + ['a';'b';'1';' ';'-';'c'] |> List.iter printChar + + // ----------------------------------------- + // FizzBuzz en utilisant les active patterns + // ----------------------------------------- + + // Vous pouvez créer un partial matching patterns également + // On utilise just un underscore dans la définition, et on retourne Some si ça correspond. + let (|MultOf3|_|) i = if i % 3 = 0 then Some MultOf3 else None + let (|MultOf5|_|) i = if i % 5 = 0 then Some MultOf5 else None + + // la fonction principale + let fizzBuzz i = + match i with + | MultOf3 & MultOf5 -> printf "FizzBuzz, " + | MultOf3 -> printf "Fizz, " + | MultOf5 -> printf "Buzz, " + | _ -> printf "%i, " i + + // test + [1..20] |> List.iter fizzBuzz + +// ================================================ +// Concision +// ================================================ + +module AlgorithmExamples = + + // F# a un haut ratio signal/bruit, permettant au code de se lire + // presque comme un véritable algorithme + + // ------ Exemple: definir une fonction sumOfSquares ------ + let sumOfSquares n = + [1..n] // 1) Prendre tous les nombres de 1 à n + |> List.map square // 2) Elever chacun d'entre eux au carré + |> List.sum // 3) Effectuer leur somme + + // test + sumOfSquares 100 |> printfn "Sum of squares = %A" + + // ------ Exemple: definir un fonction de tri ------ + let rec sort list = + match list with + // Si la liste est vide + | [] -> + [] // on retourne une liste vide + // si la list n'est pas vide + | firstElem::otherElements -> // on prend le premier élément + let smallerElements = // on extrait les éléments plus petits + otherElements // on prend les restants + |> List.filter (fun e -> e < firstElem) + |> sort // et on les trie + let largerElements = // on extrait les plus grands + otherElements // de ceux qui restent + |> List.filter (fun e -> e >= firstElem) + |> sort // et on les trie + // On combine les 3 morceaux dans une nouvelle liste que l'on retourne + List.concat [smallerElements; [firstElem]; largerElements] + + // test + sort [1;5;23;18;9;1;3] |> printfn "Sorted = %A" + +// ================================================ +// Code Asynchrone +// ================================================ + +module AsyncExample = + + // F# inclus des fonctionnalités pour aider avec le code asynchrone + // sans rencontrer la "pyramid of doom" + // + // L'exemple suivant télécharge une séquence de page web en parallèle. + + open System.Net + open System + open System.IO + open Microsoft.FSharp.Control.CommonExtensions + + // Récupérer le contenu d'une URL de manière asynchrone + let fetchUrlAsync url = + async { // Le mot clé "async" et les accolades + // créent un objet "asynchrone" + let req = WebRequest.Create(Uri(url)) + use! resp = req.AsyncGetResponse() + // use! est un assignement asynchrone + use stream = resp.GetResponseStream() + // "use" déclenche automatiquement close() + // sur les ressources à la fin du scope + use reader = new IO.StreamReader(stream) + let html = reader.ReadToEnd() + printfn "finished downloading %s" url + } + + // une liste des sites à rapporter + let sites = ["http://www.bing.com"; + "http://www.google.com"; + "http://www.microsoft.com"; + "http://www.amazon.com"; + "http://www.yahoo.com"] + + // C'est parti! + sites + |> List.map fetchUrlAsync // créez une liste de tâche asynchrone + |> Async.Parallel // dites aux tâches de tourner en parallèle + |> Async.RunSynchronously // démarrez les! + +// ================================================ +// .NET compatabilité +// ================================================ + +module NetCompatibilityExamples = + + // F# peut réaliser presque tout ce que C# peut faire, et il s'intègre + // parfaitement avec les librairies .NET ou Mono. + + // ------- Travaillez avec les fonctions des librairies existantes ------- + + let (i1success,i1) = System.Int32.TryParse("123"); + if i1success then printfn "parsed as %i" i1 else printfn "parse failed" + + // ------- Implémentez des interfaces à la volée! ------- + + // Créer un nouvel objet qui implémente IDisposable + let makeResource name = + { new System.IDisposable + with member this.Dispose() = printfn "%s disposed" name } + + let useAndDisposeResources = + use r1 = makeResource "first resource" + printfn "using first resource" + for i in [1..3] do + let resourceName = sprintf "\tinner resource %d" i + use temp = makeResource resourceName + printfn "\tdo something with %s" resourceName + use r2 = makeResource "second resource" + printfn "using second resource" + printfn "done." + + // ------- Code orienté objet ------- + + // F# est aussi un véritable language OO. + // Il supporte les classes, l'héritage, les méthodes virtuelles, etc. + + // interface avec type générique + type IEnumerator<'a> = + abstract member Current : 'a + abstract MoveNext : unit -> bool + + // Classe de base abstraite avec méthodes virtuelles + [<AbstractClass>] + type Shape() = + // propriétés en lecture seule + abstract member Width : int with get + abstract member Height : int with get + // méthode non-virtuelle + member this.BoundingArea = this.Height * this.Width + // méthode virtuelle avec implémentation de la classe de base + abstract member Print : unit -> unit + default this.Print () = printfn "I'm a shape" + + // classe concrète qui hérite de sa classe de base et surcharge + type Rectangle(x:int, y:int) = + inherit Shape() + override this.Width = x + override this.Height = y + override this.Print () = printfn "I'm a Rectangle" + + // test + let r = Rectangle(2,3) + printfn "The width is %i" r.Width + printfn "The area is %i" r.BoundingArea + r.Print() + + // ------- extension de méthode ------- + + // Juste comme en C#, F# peut étendre des classes existantes avec des extensions de méthode. + type System.String with + member this.StartsWithA = this.StartsWith "A" + + // test + let s = "Alice" + printfn "'%s' starts with an 'A' = %A" s s.StartsWithA + + // ------- événements ------- + + type MyButton() = + let clickEvent = new Event<_>() + + [<CLIEvent>] + member this.OnClick = clickEvent.Publish + + member this.TestEvent(arg) = + clickEvent.Trigger(this, arg) + + // test + let myButton = new MyButton() + myButton.OnClick.Add(fun (sender, arg) -> + printfn "Click event with arg=%O" arg) + + myButton.TestEvent("Hello World!") + +``` + +## Plus d'information + +Pour plus de démonstration de F#, rendez-vous sur le site [Try F#](http://www.tryfsharp.org/Learn), ou suivez la série [why use F#](http://fsharpforfunandprofit.com/why-use-fsharp/). + +Apprenez en davantage à propose de F# sur [fsharp.org](http://fsharp.org/). |