Inspiration fonctionnelle – Irrelevantable, partie 2
Tentons d’exprimer quelque chose de plus que Nullable<T>
Pas de soirée Craftsmanship hier soir pour moi… un peu déçu, mais au moins j’en ai profité pour avancer sur la mise en ligne de ce billet !
Il s’agit du troisième billet d’une série sur la façon dont la programmation fonctionnelle, et la formation F# à laquelle j’ai récemment assisté, m’apportent de l’inspiration dans mon travail quotidien en C#. Ce post présentera une implémentation en F# du type Irrelevantable précédemment construit en C#.
Passons directement au code, voici la structure :
type Irrelevantable<'a> = | Relevant of 'a | Absent | Irrelevant
En utilisant un simple “discriminated union type”, on peut construire sans artifice une structure gérant les trois cas nécessaires.
Voyons maintenant comment ce type peut être utilisé. Je commence par définir un type Product et une liste de produits :
type Product = { Name: string; ProductType: string; Strike: Irrelevantable<decimal>; Premium: Irrelevantable<decimal>; TradedPrice: Irrelevantable<decimal> SwapPrice: Irrelevantable<decimal>; } let products = [ { Name = "568745"; ProductType = "Option"; Strike = Relevant(176m); Premium = Relevant(3.72m); TradedPrice = Irrelevant; SwapPrice = Irrelevant } ; { Name = "568746"; ProductType = "Option"; Strike = Relevant(176m); Premium = Absent; TradedPrice = Irrelevant; SwapPrice = Irrelevant } ; { Name = "568747"; ProductType = "Swap "; Strike = Irrelevant; Premium = Irrelevant; TradedPrice = Relevant(15.3m); SwapPrice = Relevant(15.6m) } ]
L’objectif est maintenant d’afficher un rapport basé sur ces produits. Je définis pour cela quelques fonctions utilitaires et/ou de formatage :
let formatValue formatter value = match value with | Relevant(data) -> (formatter data) | Absent -> "" | Irrelevant -> "-" let padLeft (value:string) = value.PadLeft(7) let formatPrice = formatValue (fun (d:decimal) -> d.ToString("N2")) let getLine vals = System.String.Join(" | ", vals |> Seq.map padLeft) let getValues p = p.Name :: p.ProductType :: (formatPrice p.Strike) :: (formatPrice p.Premium) :: (formatPrice p.TradedPrice) :: (formatPrice p.SwapPrice) :: [] let getProductLine = getValues >> getLine
On peut remarque ici qu’en jouant avec la syntaxe F#, en plus d’utiliser l’opérateur de pipe ( |> ), j’ai également utilisé une composition de fonctions, grâce à l’opérateur >> (qui n’est pas une redirection de flux C++ !).
Et j’utilise ces fonctions pour générer les lignes à afficher, en commençant par une ligne d’en-tête :
let headerLine = ( "Ref." :: "Type" :: "Strike" :: "Premium" :: "Price" :: "Swap price" :: []) |> getLine let productLines = products |> List.map getProductLine let allLines = headerLine :: productLines
Finalement, je peux afficher le rapport :
let test = allLines |> List.iter (printfn "%s")
Et l’affichage en sortie est le suivant :
Ref. | Type | Strike | Premium | Price | Swap price
568745 | Option | 176,00 | 3,72 | - | -
568746 | Option | 176,00 | | - | -
568747 | Swap | - | - | 15,30 | 15,60
On peut alors remarquer la différence entre une valeur absente (dans la colonne Premium pour le deuxième produit), et les valeurs qui n’ont aucun sens, et qui sont représentées par un tiret.
Suivez-nous sur Twitter !
Mots-clefs
.Net agile arolla AST attitude bdd C# code code legacy craftsmanship DDD design devoxxFR discussion domain développement enum F# finance fonctionnel game html5 immutabilité Jam de Code java java8 javascript jigsaw jvm kata LINQ map mobile nodeJS polymorphism programming quality qualité scala software software craftmanship TDD TechDays testing visualizationLiens
- Arolla.fr, le site web d'Arolla
- Le blog de Cyrille Martraire, directeur technique d'Arolla
- Le blog de Nouhoum Traore, consultant Arolla
- Le blog de Pierre Irrmann, contributeur enthousiaste
- Le GitHub d'Arnauld Loyer, consultant Arolla
- Le GitHub de Germain Soumier, consultant Arolla
- Le GitHub de Jérémy Goupil, consultant Arolla
- Le GitHub de Jérôme Prudent, consultant Arolla





