Le XXIème siècle sera typé ou ne sera pas
ou Comment j'ai appris à aimer les types
Arnaud Bailly - @dr_c0d3
September 24, 2019
Plan
- Introduction
- Motivation
- Explication
- Conclusion
Introduction
Pourquoi ?
- Discussions sur le canal
#beginners
dans le slack elm-lang
: Beaucoup du questions sur le type de List a
…
- Making Impossible States Impossible
- Lien entre types et formalisation de domaines métiers
Objectif
- Faire découvrir la richesse des systèmes de types des langages fonctionnels
- Comprendre comment utiliser ces systèmes pour des programmes “normaux”
- Comprendre en quoi un système de types riche peut permettre de mieux concevoir des programmes
Motivation
Explication
Fonctions pures

- Des fonctions sans effets de bord
- De préférences totales…
- De première classe dans le langage…
- Qui sont interprétées par le runtime qui encapsule l’ensemble des effets
Fonctions pures
selectEntries : (Account -> Bool) -> Vect k Entries -> Balance
isLeapYear : Year -> Bool
toDate : String -> String -> String -> Either String Date
Types de données algébriques

- Décrit les données comme engendrées par une structure algébrique
- Types construits par composition au moyen d’opérateurs union et produit
- Un type est une fonction dans le domaine des types, un constructeur de types
- Permet au compilateur de “garantir” la totalité d’une fonction
Types de données algébriques
data Balance : Type where
Zero : Balance
Bal : (n : Amount) -> (d : Direction) -> Balance
Types de données algébriques récursifs
data List a = Nil | Cons a (List a)
Interfaces

- Interface offerte par un type de données
- Permet d’encapsuler l’implémentation concrète
- Peut exprimer des relations complexes entre plusieurs types de données
- Plus que des interfaces à la java
Interfaces
interface ToSExp a where
toSExp : a -> SExp
ToSExp SExp where
toSExp = id
ToSExp Unit where
toSExp () = SList []
Familles de types

- Relation entre types
- Rend le domaine d’une fonction dépendant du codomaine
- Peut être ouvert (relation extensible) ou fermé (le codomaine est fini)
type family Answer q = a | a -> q where
Answer QCM = Int
Answer Grade = Double
Answer OpenQuestion = Text
En Haskell, les familles des types sont une construction spéciales permettant de
définir des relations entre types
Factors : UnitType -> Type
Factors Armored = StdFactors
Factors Artillery = Arty
Factors AntiTank = Pak
Factors HQ = Arty
Factors SupplyColumn = Unit
- En Idris, les fonctions peuvent prendre des types et en retourner!
- la frontière entre types et valeurs est perméable, au moins syntaxiquement
Types existentiels

- Encapsuler un ensemble de types dans un autre type de données
- Renforce la distinction entre type abstrait et concret en rendant l’implémentation inaccessible
- Garantit la localité des opérations sur un type: la variable de type est nécessairement locale
Types existentiels
data CmdREPL : (segment : GameSegment) -> Type where
Cmd : (cmd : Command segment) -> CmdREPL segment
Qry : (ToSExp res) => (qry : Query res) -> CmdREPL segment
On cache le type exact de res
en n’exposant que son interface (ToSExp
)
data BookOfAccounts : Type where
BookTransactions : (txs : Vect k Transaction) ->
BookOfAccounts
On cache le paramètre de type k
qui indique la longueur du vecteur ce qui le rend inaccessible de “l’extérieur”
GADTs

- Applicable aux types paramétrés
- Chaque constructeur d’un type peut retourner une type différent
- Permet de spécialiser le paramètre en fonction du contexte dans lequel le type est appelé à s’insérer
GADTs
data Query : (result : Type) -> Type where
SupplyPath : (unitName : String)
-> Query (Either QueryError (List Pos))
TerrainMap : Query Map
En pattern-matchant sur le constructeur, on sait quel est le type associé result
ce qui permet de traiter ce résultat
Hole-Driven Development

- Utiliser l’inférence de type pour compléter le code par la structure attendue par le compilateur
- Permet de s’assurer dés le départ qu’une fonction est totale ou a minima que tous les cas en input sont couverts
- Permet à l’éditeur de compléter automatiquement le code
- Guide l’implémentation et parfois permet de la déduire automatiquement
Hole-Driven Development
Eq Balance where
(==) b b' = ?hole
Pour définir l’égalité entre 2 Balance
on part d’une équation minimale
- + Accounting.Core.hole [P]
`-- b : Balance
b' : Balance
--------------
Accounting.Core.hole : Bool
Types dépendants

- Faire tomber la barrière entre les types et les valeurs
- Un type peut être définit par une fonction dépendant de la valeur d’un paramètre
- Introduit une hiérarchie potentiellement infinie de types (quel est le type de
Type
?)
- Le vérificateur de types utilise la même sémantique que le runtime
Types dépendants
record GameUnit where
constructor MkGameUnit
nation : Nation
unitType : UnitType
name : String
move : Nat
hit : Bool
combat : Factors unitType
Le type de combat
est une fonction de la valeur de unitType
Type égalité

- Exprimer l’égalité entre deux types comme un type
- Le type devient une assertion logique, une proposition qui doit être vérifiée par l’implémentation
- La seule valeur qui habite ce type est
Refl
qui est donc une preuve que l’égalité est vérifiée
Type égalité
neighbours1_test : (neighbours (Hex 3 3) = [ Hex 2 3, Hex 3 2
, Hex 4 3, Hex 4 4
, Hex 3 4, Hex 2 4] )
neighbours1_test = Refl
- les types égalité peuvent servir à définir des “tests” exécutés par le compilateur
- en combinaison avec les “Trous”, cela permet de faire du TDD dans le système de types!
Type égalité
data Entries : Type where
MkEntries : (entries : Vect n Entry) ->
{ auto need2Entries : LTE 2 n } ->
{ auto balanced : balance entries = Zero } -> Entries
- ils servent surtout à exprimer des propriétés, des assertions qui sont vérifiées par le
compilateur
Types = Proposition

- Mise en oeuvre concrète de Curry-Howard
- Les types sont des propositions, les programmes des preuves
- Écrire un programme c’est démontrer que les types sont habités, que l’on peut effectivement construire des valeurs des types donnés
- De la conception de logiciels considérée comme l’énonciation de théorèmes…
Types = Proposition
notPosZIsNotAbsZ : ((y = Pos 0) -> Void) -> ((absZ y = 0) -> Void)
notPosZIsNotAbsZ = contrapositive absZIsPosZ
Proof that if a number is not 0, its absolute value is not 0
This is the contrapositive proof to absZIsPosZ
@y: a Relative number which is not 0
Types = Proposition
contrapositive : (a -> b) -> (Not b -> Not a)
contrapositive = flip (.)
Exprime la contraposée d’une proposition: Si a implique b, alors non b implique non a
Types = Proposition
absZIsPosZ : (absZ y = 0) -> (y = Pos 0)
absZIsPosZ {y = (Pos Z)} Refl = Refl
absZIsPosZ {y = (Pos (S _))} Refl impossible
absZIsPosZ {y = (NegS _)} Refl impossible
Proof that if the absolute value of a number is 0, then this number is 0
@y: a relative number which we take absolute value of
Conclusion

Conclusion
- Le système de type est un outil essentiel dans la conception du logiciel
- Les systèmes de types fonctionnels sont de plus en plus sophistiqués et permettent de modéliser des contraintes de plus en plus proches du métier
- Le XXIème sera typé !
Pub
- 2 jours de formation gratuite sur l’Architecture Fonctionnelle
- S’approprier les fondamentaux de l’architecture fonctionnelle et apprendre à les mettre en pratique dans la conception d’un logiciel.
- Paris (lieu exact TBD), les 14 et 15 novembre 2019
- Un partenariat Aleryo / Palo-IT
- Contact: arnaud@aleryo.com
Colophon
(Quelques) Références
(Quelques) Références
Credits
- Guéridon, G.Braque, 1913
- Les demoiselles d’Avignon, P.Picasso, 1907
- Composition II en rouge, bleu et jaune, P.Mondrian, 1930
- Fontaine, M.Duchamp, 1917
- Second Version of Triptych 1944, F.Bacon, 1988
- IKB 290, Y.Klein, 1959
Credits
- Orange et jaune, M.Rothko, 1956
- Dormeurs, S.Calle, 1979
- Ensemble, L.Bourgeois, 2005
- Untitled, J.Pollock, 1948
- Composition VIII, W.Kandinsky, 1923
- Suprematist Composition: White on White., K.Malevitch, 1918
- La trahison des images, R.Magritte, 1929
Feedback
Questionnaire
https://forms.gle/C1h63ymmoqdceeme7