#+Title: Introduction à la Programmation Fonctionnelle avec Haskell
#+Author: Yann Esposito
#+Email: yann@esposito.host
#+Date: <2018-03-15 Thu>
#+LANGUAGE: fr
#+LANG: fr
#+HTML_HEAD: <link rel='stylesheet' type='text/css' href='/css/slides.css' />
* Introduction à la Programmation Fonctionnelle avec Haskell
*** main :: IO ()

#+BEGIN_SRC
████████████████████████████████████████████████████████████████████████████████████
█                                                                                  █
█                        Initialiser l'env de dev                                  █
█                                                                                  █
████████████████████████████████████████████████████████████████████████████████████
#+END_SRC

Install **stack**:

#+BEGIN_SRC bash
curl -sSL https://get.haskellstack.org/ | sh
#+END_SRC

Install **nix**:

#+BEGIN_SRC bash
curl https://nixos.org/nix/install | sh
#+END_SRC

** Programmation Fonctionnelle?
*** Von Neumann Architecture (1945)

#+BEGIN_SRC
           +--------------------------------+
           | +----------------------------+ |
           | | central processing unit    | |
           | | +------------------------+ | |
           | | |     Control Unit       | | |
+------+   | | +------------------------+ | |  +--------+
|input +---> | +------------------------+ | +--> output |
+------+   | | |  Arithmetic/Logic Unit | | |  +--------+
           | | +------------------------+ | |
           | +-------+---^----------------+ |
           |         |   |                  |
           | +-------v---+----------------+ |
           | |     Memory Unit            | |
           | +----------------------------+ |
           +--------------------------------+
#+END_SRC

made with http://asciiflow.com

*** Von Neumann vs Church

- programmer à partir de la machine (Von Neumann)
  + tire vers l'optimisation
  + mots de bits, caches, détails de bas niveau
  + actions séquentielles
  + *1 siècle d'expérience*

. . .

- programmer comme manipulation de symbole (Alonzo Church)
  + tire vers l'abstraction
  + plus proche des représentations mathématiques
  + ordre d'évaluation non imposé
  + *4000 ans d'expérience*

*** Histoire

- λ-Calculus, Alonzo Church & Rosser 1936
  - Foundation, explicit side effect no implicit state

. . .

- LISP (McCarthy 1960)
  - Garbage collection, higher order functions, dynamic typing

. . .

- ML (1969-80)
  - Static typing, Algebraic Datatypes, Pattern matching

. . .

- Miranda (1986) → Haskell (1992‥)
  - Lazy evaluation, pure

** Pourquoi Haskell?
*** Simplicité par l'abstraction

 *=/!\= SIMPLICITÉ ≠ FACILITÉ =/!\=*

- mémoire (garbage collection)
- ordre d'évaluation (non strict / lazy)
- effets de bords (pur)
- manipulation de code (referential transparency)

. . .

Simplicité: Probablement le meilleur indicateur de réussite de projet.

*** Production Ready™

- rapide
  - équivalent à Java (~ x2 du C)
  - parfois plus rapide que C
  - bien plus rapide que python et ruby
. . .
- communauté solide
  - 3k comptes sur Haskellers
  - >30k sur reddit /(35k rust, 45k go, 50k nodejs, 4k ocaml, 13k clojure)/
  - libs >12k sur hackage
. . .
- entreprises
  - Facebook (fighting spam, HAXL, ...)
  - beaucoup de startups, finance en général
. . .
- milieu académique
  - fondations mathématiques
  - fortes influences des chercheurs
  - tire le langage vers le haut

*** Tooling

- compilateur (GHC)
- gestion de projets ; cabal, stack, hpack, etc...
- IDE / hlint ; rapidité des erreurs en cours de frappe
- frameworks hors catégorie (servant, yesod)
- ecosystèmes très matures et inovant
  - Elm (⇒ frontend)
  - Purescript (⇒ frontend)
  - GHCJS (⇒ frontend)
  - Idris (types dépendants)
  - Hackett (typed LISP avec macros)
  - Eta (⇒ JVM)

*** Qualité

#+BEGIN_QUOTE
/Si ça compile alors il probable que ça marche/
#+END_QUOTE
. . .
- tests unitaires :
  chercher quelques erreurs manuellements
. . .
- /test génératifs/ :
  chercher des erreurs sur beaucoups de cas générés aléatoirements
  & aide pour trouver l'erreur sur l'objet le plus simple
. . .
- /finite state machine generative testing/ :
  chercher des erreurs sur le déroulement des actions
  entre différents agents indépendants
. . .
- *preuves*:
  chercher des erreur sur *TOUTES* les entrées possibles
  possible à l'aide du système de typage

* Premiers Pas en Haskell
*** DON'T PANIC

#+BEGIN_SRC
██████╗  ██████╗ ███╗   ██╗████████╗    ██████╗  █████╗ ███╗   ██╗██╗ ██████╗██╗
██╔══██╗██╔═══██╗████╗  ██║╚══██╔══╝    ██╔══██╗██╔══██╗████╗  ██║██║██╔════╝██║
██║  ██║██║   ██║██╔██╗ ██║   ██║       ██████╔╝███████║██╔██╗ ██║██║██║     ██║
██║  ██║██║   ██║██║╚██╗██║   ██║       ██╔═══╝ ██╔══██║██║╚██╗██║██║██║     ╚═╝
██████╔╝╚██████╔╝██║ ╚████║   ██║       ██║     ██║  ██║██║ ╚████║██║╚██████╗██╗
╚═════╝  ╚═════╝ ╚═╝  ╚═══╝   ╚═╝       ╚═╝     ╚═╝  ╚═╝╚═╝  ╚═══╝╚═╝ ╚═════╝╚═╝
#+END_SRC

- Haskell peut être difficile à vraiment maîtriser
- Trois languages en un:
  - Fonctionnel
  - Imperatif
  - Types
- Polymorphisme:
  - contexte souvent semi-implicite change le comportement du code.

*** Fichier de script isolé

Avec Stack: https://haskellstack.org

#+BEGIN_SRC haskell
#!/usr/bin/env stack
{- stack script
   --resolver lts-12.10
   --install-ghc
   --package protolude
-}
#+END_SRC

Avec Nix: https://nixos.org/nix/

#+BEGIN_SRC shell
#! /usr/bin/env nix-shell
#! nix-shell -i runghc
#! nix-shell -p "ghc.withPackages (ps: [ ps.protolude ])"
#! nix-shell -I nixpkgs="https://github.com/NixOS/nixpkgs/archive/18.09.tar.gz"
#+END_SRC

*** Hello World! (1/3)

#+BEGIN_SRC haskell
-- hello.hs
main :: IO ()
main = putStrLn "Hello World!"
#+END_SRC

#+BEGIN_SRC
> chmod +x hello.hs
> ./hello.hs
Hello World!
#+END_SRC

#+BEGIN_SRC
> stack ghc -- hello.hs
> ./hello
Hello World!
#+END_SRC

*** Hello World! (2/3)

#+BEGIN_SRC haskell
main :: IO ()
main = putStrLn "Hello World!"
#+END_SRC

- ~::~ de type ;
- le type de ~main~ est ~IO ()~.
- ~=~ égalité (la vrai, on peut interchanger ce qu'il y a des deux cotés) ;
- le type de ~putStrLn~ est ~String -> IO ()~ ;
- application de fonction =f x= pas =f(x)=, pas de parenthèse nécessaire ;

*** Hello World! (3/3)

#+BEGIN_SRC haskell
main :: IO ()
main = putStrLn "Hello World!"
#+END_SRC

- Le type ~IO a~ signifie: C'est une description d'une procédure qui quand elle
  est évaluée peut faire des actions d'IO qui retournera une valeur de type ~a~ ;
- ~main~ est le nom du point d'entrée du programme ;
- Haskell runtime va chercher pour ~main~ et l'exécute.

** What is your name?
*** What is your name? (1/2)

#+BEGIN_SRC haskell
main :: IO ()
main = do
  putStrLn "Hello! What is your name?"
  name <- getLine
  let output = "Nice to meet you, " ++ name ++ "!"
  putStrLn output
#+END_SRC

. . .

- l'indentation est importante !
- ~do~ commence une syntaxe spéciale qui permet de séquencer des actions ~IO~ ;
- le type de ~getLine~ est ~IO String~ ;
- ~IO String~ signifie: Ceci est la description d'une procédure qui lorsqu'elle
  est évaluée peut faire des actions IO et retourne une valeur de type ~String~.

*** What is your name? (2/2)

#+BEGIN_SRC haskell
main :: IO ()
main = do
  putStrLn "Hello! What is your name?"
  name <- getLine
  let output = "Nice to meet you, " ++ name ++ "!"
  putStrLn output
#+END_SRC

- le type de ~getLine~ est ~IO String~
- le type de ~name~ est ~String~
- ~<-~ est une syntaxe spéciale qui n'apparait que dans la notation ~do~
- ~<-~ signifie: évalue la procédure et attache la valeur renvoyée dans le nom
  à gauche de ~<-~
- ~let <name> = <expr>~ signifie que ~name~ est interchangeable avec ~expr~ pour
  le reste du bloc ~do~.
- dans un bloc ~do~, ~let~ n'a pas besoin d'être accompagné par ~in~ à la fin.

** Erreurs classiques
*** Erreur classique #1

#+BEGIN_SRC haskell
main :: IO ()
main = do
  putStrLn "Hello! What is your name?"
  let output = "Nice to meet you, " ++ getLine ++ "!"
  putStrLn output
#+END_SRC

#+BEGIN_SRC
/Users/yaesposi/.deft/pres-haskell/name.hs:6:40: warning: [-Wdeferred-type-errors]
    • Couldn't match expected type ‘[Char]’
                  with actual type ‘IO String’
    • In the first argument of ‘(++)’, namely ‘getLine’
      In the second argument of ‘(++)’, namely ‘getLine ++ "!"’
      In the expression: "Nice to meet you, " ++ getLine ++ "!"
  |
6 |   let output = "Nice to meet you, " ++ getLine ++ "!"
  |                                        ^^^^^^^
Ok, one module loaded.
#+END_SRC

*** Erreur classique #1

- ~String~ est ~[Char]~
- Haskell n'arrive pas à faire matcher le type ~String~ avec ~IO String~.
- ~IO a~ et ~a~ sont différents

*** Erreur classique #2

#+BEGIN_SRC haskell
main :: IO ()
main = do
  putStrLn "Hello! What is your name?"
  name <- getLine
  putStrLn  "Nice to meet you, " ++ name ++ "!"
#+END_SRC

#+BEGIN_SRC
/Users/yaesposi/.deft/pres-haskell/name.hs:7:3: warning: [-Wdeferred-type-errors]
    • Couldn't match expected type ‘[Char]’ with actual type ‘IO ()’
    • In the first argument of ‘(++)’, namely
        ‘putStrLn "Nice to meet you, "’
      In a stmt of a 'do' block:
        putStrLn "Nice to meet you, " ++ name ++ "!"
      In the expression:
        do putStrLn "Hello! What is your name?"
           name <- getLine
           putStrLn "Nice to meet you, " ++ name ++ "!"
  |
7 |   putStrLn "Nice to meet you, " ++ name ++ "!"
#+END_SRC

*** Erreur classique #2 (fix)

- Des parenthèses sont nécessaires
- L'application de fonction se fait de gauche à droite

#+BEGIN_SRC haskell
main :: IO ()
main = do
  putStrLn "Hello! What is your name?"
  name <- getLine
  putStrLn ("Nice to meet you, " ++ name ++ "!")
#+END_SRC

* Concepts avec exemples
*** Concepts
- /style déclaratif & récursif/
- /immutabilité/
- /pureté/ (par défaut)
- /evaluation paraisseuse/ (par défaut)
- /ADT & typage polymorphique/

*** /Style déclaratif & récursif/

#+BEGIN_SRC python
>>> x=0
... for i in range(1,11):
...     tmp = i*i
...     if tmp%2 == 0:
...       x += tmp
>>> x
220
#+END_SRC

#+BEGIN_SRC haskell
-- (.) composition (de droite à gauche)
Prelude> sum . filter even . map (^2) $ [1..10]
220
Prelude> :set -XNoImplicitPrelude
Prelude> import Protolude
-- (&) flipped fn application (de gauche à droite)
Protolude> [1..10] & map (^2) & filter even & sum
220
#+END_SRC

*** /Style déclaratif & récursif/

#+BEGIN_SRC python
>>> x=0
... for i in range(1,11):
...     j = i*3
...     tmp = j*j
...     if tmp%2 == 0:
...       x += tmp
#+END_SRC

#+BEGIN_SRC haskell
Prelude> sum . filter even . map (^2) . map (*3) $ [1..10]
Protolude> [1..10] & map (*3) & map (^2) & filter even & sum
#+END_SRC

*** /Style déclaratif & récursif/

- Contrairement aux languages impératifs la récursion n'est généralement pas chère.
- tail recursive function, mais aussi à l'aide de la lazyness

*** /Imutabilité/

#+BEGIN_SRC haskell
-- | explicit recursivity
incrementAllEvenNumbers :: [Int] -> [Int]
incrementAllEvenNumbers (x:xs) = y:incrementAllEvenNumbers xs
  where y = if even x then x+1 else x

-- | better with use of higher order functions
incrementAllEvenNumbers' :: [Int] -> [Int]
incrementAllEvenNumbers' ls = map incrementIfEven ls
  where
   incrementIfEven :: Int -> Int
   incrementIfEven x = if even x then x+1 else x
#+END_SRC

*** /Pureté/: Function vs Procedure/Subroutines

- Une /fonction/ n'a pas d'effet de bord
- Une /Procedure/ ou /subroutine/ but engendrer des effets de bords lors de son
  évaluation

*** /Pureté/: Function vs Procedure/Subroutines (exemple)

#+BEGIN_SRC haskell
dist :: Double -> Double -> Double
dist x y = sqrt (x**2 + y**2)
#+END_SRC


#+BEGIN_SRC haskell
getName :: IO String
getName = readLine
#+END_SRC

- *IO a* ⇒ *IMPUR* ; effets de bords hors evaluation :
  - lire un fichier ;
  - écrire sur le terminal ;
  - changer la valeur d'une variable en RAM est impur.

*** /Pureté/: Gain, paralellisation gratuite

#+BEGIN_SRC haskell
import Foreign.Lib (f)
--  f :: Int -> Int
--  f = ???

foo = sum results
  where results = map f [1..100]
#+END_SRC

. . .

*~pmap~ FTW!!!!! Assurance d'avoir le même résultat avec 32 cœurs*

#+BEGIN_SRC haskell
import Foreign.Lib (f)
--  f :: Int -> Int
--  f = ???

foo = sum results
  where results = pmap f [1..100]
#+END_SRC

*** /Pureté/: Structures de données immuable

Purely functional data structures,
/Chris Okasaki/

Thèse en 1996, et un livre.

Opérations sur les listes, tableaux, arbres
de complexité amortie equivalent ou proche
(pire des cas facteur log(n))
de celle des structures de données muables.

*** /Évaluation parraisseuse/: Stratégies d'évaluations

=(h (f a) (g b))= peut s'évaluer:

- =a= → =(f a)= → =b= → =(g b)= → =(h (f a) (g b))=
- =b= → =a= → =(g b)= → =(f a)= → =(h (f a) (g b))=
- =a= et =b= en parallèle puis  =(f a)= et =(g b)= en parallèle et finallement
  =(h (f a) (g b))=
- =h= → =(f a)= seulement si nécessaire et puis =(g b)= seulement si nécessaire

Par exemple: =(def h (λx.λy.(+ x x)))= il n'est pas nécessaire d'évaluer =y=,
dans notre cas =(g b)=

*** /Évaluation parraisseuse/: Exemple

#+BEGIN_SRC haskell
quickSort [] = []
quickSort (x:xs) = quickSort (filter (<x) xs)
                   ++ [x]
                   ++ quickSort (filter (>=x) xs)

minimum list = head (quickSort list)
#+END_SRC

Un appel à ~minimum longList~ ne vas pas ordonner toute la liste.
Le travail s'arrêtera dès que le premier élément de la liste ordonnée sera trouvé.

~take k (quickSort list)~ est en ~O(n + k log k)~ où ~n = length list~.
Alors qu'avec une évaluation stricte: ~O(n log n)~.

*** /Évaluation parraisseuse/: Structures de données infinies (zip)

#+BEGIN_SRC haskell
zip :: [a] -> [b] -> [(a,b)]
zip [] _  = []
zip _  [] = []
zip (x:xs) (y:ys) = (x,y):zip xs ys
#+END_SRC

#+BEGIN_SRC haskell
zip [1..] ['a','b','c']
#+END_SRC

s'arrête et renvoie :

#+BEGIN_SRC haskell
[(1,'a'), (2,'b'), (3, 'c')]
#+END_SRC

*** /Évaluation parraisseuse/: Structures de données infinies (2)

#+BEGIN_SRC haskell
Prelude> zipWith (+) [0,1,2,3] [10,100,1000]
[10,101,1002]
Prelude> take 3 [1,2,3,4,5,6,7,8,9]
[1,2,3]
#+END_SRC

#+BEGIN_SRC haskell
Prelude> fib = 0:1:(zipWith (+) fib (tail fib))
Prelude> take 10 fib
[0,1,1,2,3,5,8,13,21,34]
#+END_SRC

*** /ADT & Typage polymorphique/

Algebraic Data Types.

#+BEGIN_SRC haskell
data Void = Void Void -- 0 valeur possible!
data Unit = ()        -- 1 seule valeur possible

data Product x y = P x y
data Sum x y = S1 x | S2 y
#+END_SRC

Soit ~#x~ le nombre de valeurs possibles pour le type ~x~
alors:

- ~#(Product x y) = #x * #y~
- ~#(Sum x y)     = #x + #y~

*** /ADT & Typage polymorphique/: Inférence de type

À partir de :

#+BEGIN_SRC haskell
zip [] _  = []
zip _  [] = []
zip (x:xs) (y:ys) = (x,y):zip xs ys
#+END_SRC

le compilateur peut déduire:

#+BEGIN_SRC haskell
zip :: [a] -> [b] -> [(a,b)]
#+END_SRC

** Composabilité
*** Composabilité vs Modularité

Modularité: soit un ~a~ et un ~b~, je peux faire un ~c~.
  ex: x un graphique, y une barre de menu => une page
      ~let page = mkPage ( graphique, menu )~

Composabilité: soit deux ~a~ je peux faire un autre ~a~.
  ex: x un widget, y un widget => un widget
      ~let page = x <+> y~

Gain d'abstraction, moindre coût.

*Hypothèses fortes sur les ~a~*

*** Exemples

- *Semi-groupes* 〈+〉
- *Monoides* 〈0,+〉

- *Catégories*  〈obj(C),hom(C),∘〉
- Foncteurs ~fmap~ (~(<$>)~)
- Foncteurs Applicatifs ~ap~ (~(<*>)~)
- Monades ~join~
- Traversables ~map~
- Foldables ~reduce~

* Catégories de bugs évités avec Haskell

*** Real Productions Bugs™

Bug vu des dizaines de fois en prod malgré:

  1. specifications fonctionnelles
  2. spécifications techniques
  3. tests unitaires
  4. 3 envs, dev, recette/staging/pre-prod, prod
  5. Équipe de QA qui teste en recette

Solutions simples.

*** **Null Pointer Exception**: Erreur classique (1)

Au début du projet :

#+BEGIN_SRC javascript
int foo( x ) {
  return x + 1;
}
#+END_SRC

*** **Null Pointer Exception**: Erreur classique (2)

Après quelques semaines/mois/années :

#+BEGIN_SRC javascript
import do_shit_1 from "foreign-module";
int foo( x ) {
  ...
  var y = do_shit_1(x);
  ...
  return do_shit_20(y)
}
...
var val = foo(26/2334 - Math.sqrt(2));
#+END_SRC

. . .

#+BEGIN_SRC
███████       █████    ███     ███ ███       ███ ███ ███ ███ ███ ███
███   ██    ███   ███  ███     ███ ████     ████ ███ ███ ███ ███ ███
███   ██   ███     ███ ███     ███ █████   █████ ███ ███ ███ ███ ███
███████    ███     ███ ███     ███ ███ █████ ███ ███ ███ ███ ███ ███
███   ███  ███     ███ ███     ███ ███  ███  ███ ███ ███ ███ ███ ███
███    ███ ███     ███ ███     ███ ███   █   ███  █   █   █   █   █
███   ███   ███   ███   ███   ███  ███       ███
███████       █████       █████    ███       ███ ███ ███ ███ ███ ███
#+END_SRC

| *Null Pointer Exception*

*** Null Pointer Exception: Data type ~Maybe~

#+BEGIN_SRC haskell
data Maybe a = Just a | Nothing
...
foo :: Maybe a
...
myFunc x = let t = foo x in
  case t of
    Just someValue -> doThingsWith someValue
    Nothing -> doThingWhenNothingIsReturned
#+END_SRC

Le compilateur oblige à tenir compte des cas particuliers!
Impossible d'oublier.

*** Null Pointer Exception: Etat

- Rendre impossibe de fabriquer un état qui devrait être impossible d'avoir.
- Pour aller plus loin voir, FRP, CQRS/ES, Elm-architecture, etc...

*** Erreur due à une typo

#+BEGIN_SRC haskell
data Foo x = LongNameWithPossibleError x
...
foo (LongNameWithPosibleError x) = ...
#+END_SRC

*Erreur à la compilation*:
Le nom d'un champ n'est pas une string
(voir les objets JSON).

*** Echange de parameters

#+BEGIN_SRC haskell
data Personne = Personne { uid :: Int, age :: Int }
foo :: Int -> Int -> Personne -- ??? uid ou age?
#+END_SRC

#+BEGIN_SRC haskell
newtype UID = UID Int deriving (Eq)
data Personne = Personne { uid :: UID, age :: Int }
foo :: UDI -> Int -> Personne -- Impossible de confondre
#+END_SRC

*** Changement intempestif d'un Etat Global

#+BEGIN_SRC haskell
foo :: GlobalState -> x
#+END_SRC

*~foo~ ne peut pas changer =GlobalState=*

* Organisation du Code
*** Grands Concepts

Procedure vs Functions:

| Gestion d'une configuration globale    |
| Gestion d'un état global              |
| Gestion des Erreurs                   |
| Gestion des IO                        |

*** Monades

Pour chacun de ces /problèmes/ il existe une monade:

| Gestion d'une configuration globale | ~Reader~ |
| Gestion d'un état global            | ~State~  |
| Gestion des Erreurs                 | ~Either~ |
| Gestion des IO                      | ~IO~     |

*** Effets

Gestion de plusieurs Effets dans la même fonction:

- MTL
- Free Monad
- Freer Monad

Idée: donner à certaines sous-fonction accès à une partie des effets seulement.

Par exemple:
- limiter une fonction à la lecture de la DB mais pas l'écriture.
- limiter l'écriture à une seule table
- interdire l'écriture de logs
- interdire l'écriture sur le disque dur
- etc...

*** Exemple dans un code réel (1)

#+BEGIN_SRC haskell
-- | ConsumerBot type, the main monad in which the bot code is written with.
-- Provide config, state, logs and IO
type ConsumerBot m a =
  ( MonadState ConsumerState m
  , MonadReader ConsumerConf m
  , MonadLog (WithSeverity Doc) m
  , MonadBaseControl IO m
  , MonadSleep m
  , MonadPubSub m
  , MonadIO m
  ) => m a
#+END_SRC

*** Exemple dans un code réel (2)

#+BEGIN_SRC haskell
bot :: Manager
    -> RotatingLog
    -> Chan RedditComment
    -> TVar RedbotConfs
    -> Severity
    -> IO ()
bot manager rotLog pubsub redbots minSeverity = do
  TC.setDefaultPersist TC.filePersist
  let conf = ConsumerConf
             { rhconf = RedditHttpConf { _connMgr = manager }
             , commentStream = pubsub
             }
  void $ autobot
       & flip runReaderT conf
       & flip runStateT (initState redbots)
       & flip runLoggingT (renderLog minSeverity rotLog)
#+END_SRC


** Règles *pragmatiques*

*** Organisation en fonction de la complexité

#+BEGIN_QUOTE
Make it work, make it right, make it fast
#+END_QUOTE

- Simple: directement IO (YOLO!)
- Medium: Haskell Design Patterns: The Handle Pattern:
  https://jaspervdj.be/posts/2018-03-08-handle-pattern.html
- Medium (bis): MTL / Free / Freeer / Effects...
- Gros: Three Layer Haskell Cake:
 http://www.parsonsmatt.org/2018/03/22/three_layer_haskell_cake.html
  + Layer 1: Imperatif
  + Orienté Objet (Level 2 / 2')
  + Fonctionnel

*** 3 couches

- *Imperatif*:
  ReaderT IO
  + Insérer l'état dans une ~TVar~, ~MVar~ ou ~IORef~ (concurrence)
- *Orienté Objet*:
  + Handle / MTL / Free...
  + donner des access ~UserDB~, ~AccessTime~, ~APIHTTP~...
- *Fonctionnel*: Business Logic ~f : Handlers -> Inputs -> Command~

*** Services / Lib

Service: ~init~ / ~start~ / ~close~ + methodes...
Lib: methodes sans état interne.

* Conclusion
*** Pourquoi Haskell?

- avantage compétitif: qualité & productivité hors norme
- change son approche de la programmation
- les concepts appris sont utilisables dans tous les languages
- permet d'aller là où aucun autre langage ne peut vous amener
- Approfondissement sans fin:
  - Théorie: théorie des catégories, théorie des types homotopiques, etc...
  - Optim: compilateur
  - Qualité: tests, preuves
  - Organisation: capacité de contraindre de très haut vers très bas

*** Avantage compétitif

- France, Europe du sud & Functional Programming
- Coût Maintenance >> production d'un nouveau produit
- Coût de la refactorisation
- "Make it work, Make it right, Make it fast" moins cher.

*** Pour la suite

A chacun de choisir, livres, tutoriels, videos, chat, etc...

- Voici une liste de resources : https://www.haskell.org/documentation
- Mon tuto rapide : [[http://yannesposito.com/Scratch/en/blog/Haskell-the-Hard-Way/][Haskell the Hard Way]]
- Moteurs de recherche par type : [[http://hayoo.fh-wedel.de][hayoo]] & [[http://haskell.org/hoogle][hoogle]]
- Communauté & News : http://haskell.org/news & ~#haskell-fr~ sur freenode
- Libs: https://hackage.haskell.org & https://stackage.org

* Appendix
*** STM: Exemple (Concurrence) (1/2)

#+BEGIN_SRC java
class Account {
  float balance;
  synchronized void deposit(float amount){
    balance += amount; }
  synchronized void withdraw(float amount){
    if (balance < amount) throw new OutOfMoneyError();
    balance -= amount; }
  synchronized void transfert(Account other, float amount){
    other.withdraw(amount);
    this.deposit(amount); }
}
#+END_SRC

Situation d'interblocage typique. (A transfert vers B et B vers A).

*** STM: Exemple (Concurrence) (2/2)

#+BEGIN_SRC haskell
deposit :: TVar Int -> Int -> STM ()
deposit acc n = do
  bal <- readTVar acc
  writeTVar acc (bal + n)
withdraw :: TVar Int -> Int -> STM ()
withdraw acc n = do
  bal <- readTVar acc
  if bal < n then retry
  writeTVar acc (bal - n)
transfer :: TVar Int -> TVar Int -> Int -> STM ()
transfer from to n = do
  withdraw from n
  deposit to n
#+END_SRC

- pas de lock explicite, composition naturelle dans ~transfer~.
- si une des deux opération échoue toute la transaction échoue
- le système de type force cette opération a être atomique:
   ~atomically :: STM a -> IO a~
