diff --git a/README.beamer.pdf b/README.beamer.pdf index dcd4b0b..5c48c4f 100644 Binary files a/README.beamer.pdf and b/README.beamer.pdf differ diff --git a/README.pdf b/README.pdf index 94bd367..53e73a3 100644 Binary files a/README.pdf and b/README.pdf differ diff --git a/compile.hs b/compile.hs index 23ac1ff..4523976 100755 --- a/compile.hs +++ b/compile.hs @@ -60,7 +60,7 @@ main = do -- | Find Markdown Files (skip hidden directories) findMarkdownFiles :: Shell FilePath findMarkdownFiles = do - fic <- find (suffix ".md") "." & fgrep (invert (prefix "./.")) + fic <- find (choice [(suffix ".md"), (suffix ".org")]) "." & fgrep (invert (prefix "./.")) let mf = stripPrefix "./" fic _ <- guard (isJust mf) return (fromJust mf) diff --git a/druid/druid.beamer.pdf b/druid/druid.beamer.pdf index 23440e7..ad15cd1 100644 Binary files a/druid/druid.beamer.pdf and b/druid/druid.beamer.pdf differ diff --git a/druid/druid.html b/druid/druid.html index 00c9407..f4886c9 100644 --- a/druid/druid.html +++ b/druid/druid.html @@ -15,8 +15,8 @@
Yann Esposito
7 Avril 2016
mkdocs
26 July 2016
<2018-03-15 Thu>
Maybe
Initialiser l’env de dev:
curl -sSL https://get.haskellstack.org/ | sh +stack new ipfh https://git.io/vbpej && \ +cd ipfh && \ +stack setup && \ +stack build && \ +stack test && \ +stack bench +
+--------------------------------+ + | +----------------------------+ | + | | central processing unit | | + | | +------------------------+ | | + | | | Control Unit | | | ++------+ | | +------------------------+ | | +--------+ +|input +---> | +------------------------+ | +--> output | ++------+ | | | Arithmetic/Logic Unit | | | +--------+ + | | +------------------------+ | | + | +-------+---^----------------+ | + | | | | + | +-------v---+----------------+ | + | | Memory Unit | | + | +----------------------------+ | + +--------------------------------+ +
made with http://asciiflow.com
pieds nus (code machine, ASM)
_ + / \ + /. ) _ + ___/ | / / \ +.-'__/ |( ( .\ + \ | \___ + )| \__`-. +
Talons hauts (C, Pascal, Java, C++, Perl, PHP, Python, Ruby, etc…)
Tennis (Clojure, Scheme, LISP, etc…)
Voiture (Haskell, Purescript, etc…)
/!\ SIMPLICITÉ ≠ FACILITÉ /!\
/!\
+Si ça compile alors il probable que ça marche +
Si ça compile alors il probable que ça marche
module Main where + +main :: IO () +main = putStrLn "Hello World!"
file:~/.deft/pres-haskell/hello.hs
::
=
putStrLn
String -> IO ()
main
IO ()
IO a
a
module Main where + +main :: IO () +main = do + putStrLn "Hello! What is your name?" + name <- getLine + let output = "Nice to meet you, " ++ name ++ "!" + putStrLn output
file:pres-haskell/name.hs
do
IO
getLine
IO String
String
name
<-
let <name> = <expr>
expr
let
in
module Main where + +main :: IO () +main = do + putStrLn "Hello! What is your name?" + let output = "Nice to meet you, " ++ getLine ++ "!" + putStrLn output
/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. +
[Char]
module Main where + +main :: IO () +main = do + putStrLn "Hello! What is your name?" + name <- getLine + putStrLn "Nice to meet you, " ++ name ++ "!"
/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 ++ "!" +
module Main where + +main :: IO () +main = do + putStrLn "Hello! What is your name?" + name <- getLine + putStrLn ("Nice to meet you, " ++ name ++ "!")
dist :: Double -> Double -> Double +dist x y = sqrt (x**2 + y**2)
getName :: IO String +getName = readLine
import Foreign.Lib (f) +-- f :: Int -> Int +-- f = ??? + +foo = sum results + where results = map f [1..100]
fmap FTW!!!!! Assurance d’avoir le même résultat avec 32 cœurs
fmap
import Foreign.Lib (f) +-- f :: Int -> Int +-- f = ??? + +foo = sum results + where results = fmap f [1..100]
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.
(h (f a) (g b)) peut s’évaluer:
(h (f a) (g b))
(f a)
b
(g b)
h
Par exemple: (def h (λx.λy.(+ x x))) il n’est pas nécessaire d’évaluer y, dans notre cas (g b)
(def h (λx.λy.(+ x x)))
y
quickSort [] = [] +quickSort (x:xs) = quickSort (filter (<x) xs) + ++ [x] + ++ quickSort (filter (>=x) xs) + +minimum list = head (quickSort list)
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é.
minimum longList
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).
take k (quickSort list)
O(n + k log k)
n = length list
O(n log n)
zip :: [a] -> [b] -> [(a,b)] +zip [] _ = [] +zip _ [] = [] +zip (x:xs) (y:ys) = (x,y):zip xs ys
zip [1..] ['a','b','c']
s’arrête et renvoie :
[(1,'a'), (2,'b'), (3, 'c')]
Algebraic Data Types.
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
Soit #x le nombre de valeurs possibles pour le type x alors:
#x
x
#(Product x y) = #x * #y
#(Sum x y) = #x + #y
À partir de :
zip [] _ = [] +zip _ [] = [] +zip (x:xs) (y:ys) = (x,y):zip xs ys
le compilateur peut déduire:
zip :: [a] -> [b] -> [(a,b)]
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 )
c
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
let page = x <+> y
Gain d’abstraction, moindre coût.
Hypothèses fortes sur les a
Monoides 〈0,+〉
(<$>)
ap
(<*>)
join
map
Foldables reduce
reduce
Bug vu des dizaines de fois en prod malgré:
Solutions simples.
int foo( x ) { + return x + 1; +}
int foo( x ) { + ... + var y = do_shit_1(x); + ... + return do_shit_20(x) +} +... +var val = foo(26/2334 - Math.sqrt(2));
888888b. .d88888b. 888 888 888b d888 888 888 888 888 888 +888 "88b d88P" "Y88b 888 888 8888b d8888 888 888 888 888 888 +888 .88P 888 888 888 888 88888b.d88888 888 888 888 888 888 +8888888K. 888 888 888 888 888Y88888P888 888 888 888 888 888 +888 "Y88b 888 888 888 888 888 Y888P 888 888 888 888 888 888 +888 888 888 888 888 888 888 Y8P 888 Y8P Y8P Y8P Y8P Y8P +888 d88P Y88b. .d88P Y88b. .d88P 888 " 888 " " " " " +8888888P" "Y88888P" "Y88888P" 888 888 888 888 888 888 888 +
Null Pointer Exception
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
Le compilateur oblige à tenir compte des cas particuliers! Impossible d’oublier.
data Foo x = LongNameWithPossibleError x +... +foo (LongNameWithPosibleError x) = ...
Erreur à la compilation: Le nom d’un champ n’est pas une string (voir les objets JSON).
data Personne = Personne { uid :: Int, age :: Int } +foo :: Int -> Int -> Personne -- ??? uid ou age?
newtype UID = UID Int deriving (Eq) +data Personne = Personne { uid :: UID, age :: Int } +foo :: UDI -> Int -> Personne -- Impossible de confondre
foo :: GlobalState -> x
foo ne peut pas changer GlobalState
foo
GlobalState
Procedure vs Functions:
Pour chacun de ces problèmes il existe une monade:
Reader
State
Either
Gestion de plusieurs Effets dans la même fonction:
Idée: donner à certaines sous-fonction accès à une partie des effets seulement.
Par exemple:
-- | 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
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)
+Make it work, make it right, make it fast +
Make it work, make it right, make it fast
TVar
MVar
IORef
UserDB
AccessTime
APIHTTP
f : Handlers -> Inputs -> Command
Service: init / start / close + methodes… Lib: methodes sans état interne.
init
start
close
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); } +}
Situation d’interblocage typique. (A transfert vers B et B vers A).
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
transfer
atomically :: STM a -> IO a
+
Initialiser l'env de dev:
Talons hauts (C, Pascal, Java, C++, Perl, PHP, Python, Ruby, etc...)
Tennis (Clojure, Scheme, LISP, etc...)
Voiture (Haskell, Purescript, etc...)
fmap FTW!!!!! Assurance d'avoir le même résultat avec 32 cœurs
(h (f a) (g b)) peut s'évaluer:
Par exemple: (def h (λx.λy.(+ x x))) il n'est pas nécessaire d'évaluer y, dans notre cas (g b)
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).
s'arrête et renvoie :
Gain d'abstraction, moindre coût.
Le compilateur oblige à tenir compte des cas particuliers! Impossible d'oublier.
Erreur à la compilation: Le nom d'un champ n'est pas une string (voir les objets JSON).
Service: init / start / close + methodes... Lib: methodes sans état interne.
Situation d'interblocage typique. (A transfert vers B et B vers A).
PDF Version