commit 4e1befea7b0c9fbf14dc094d9b28310d45103e39 Author: Yann Esposito (Yogsototh) Date: Thu Aug 24 20:58:13 2017 +0200 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ee585e86 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +ltximg diff --git a/Archive.org.gpg b/Archive.org.gpg new file mode 100644 index 00000000..fa57ee9c Binary files /dev/null and b/Archive.org.gpg differ diff --git a/Cisco.org.gpg b/Cisco.org.gpg new file mode 100644 index 00000000..37ecc812 Binary files /dev/null and b/Cisco.org.gpg differ diff --git a/Deep-Learning.org b/Deep-Learning.org new file mode 100644 index 00000000..35a62f6e --- /dev/null +++ b/Deep-Learning.org @@ -0,0 +1,218 @@ +-- #+TITLE: Deep Learning Coursera +-- #+AUTHOR: Yann Esposito +#+STARTUP: latexpreview +#+TODO: TODO IN-PROGRESS WAITING | DONE CANCELED +#+COLUMNS: %TODO %3PRIORITY %40ITEM(Task) %17Effort(Estimated Effort){:} %CLOCKSUM %8TAGS(TAG) + +* Plan + +5 courses + +** Neural Network and Deep Learning +*** Week 1: Introduction +*** Week 2: Basic of Neural Network programming +*** Week 3: One hidden layer Neural Networks +*** Week 4: Deep Neural Network +** Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization +** Structuring your Machine Learning project +** Convolutional Neural Networks +** Natural Language Processing: Building sequence models +* DONE Neural Network and Deep Learning + CLOSED: [2017-08-22 Tue 13:43] +** Introduction + +*** What is a neural network? + +*** Supervised Learning with Neural Networks + + - Lucrative application: ads, showing the add you're most likely to click on + - Photo tagging + - Speech recognition + - Machine translation + - Autonomous driving + + +***** Convolutional NN good for images + +***** Strutured data (db of data) vs Unstructured data + + - Structured data: Tables + - Unstructured data: Audio, image, text... + + Computer are much better at interpreting unstructured data. + +*** Why is Deep Learning taking off? + + [[///Users/yaesposi/Library/Mobile%20Documents/com~apple~CloudDocs/deft/img/Scale%20drives%20deep%20learning%20progress.png]] + + - Data (lot of data) + - Computation (faster learning loop) + - Algorithms (ex, use ReLU instead of sigma) +** Geoffrey Hinton interview +** Binary Classification + +\[ (x,y) x\in \mathbb{R}^{n_x}, y \in {0,1} \] + +$m$ training examples: $$ {(x^{(1)},y^{(1)}), ... (x^{(m)},y^{(m)})} $$ + +$$ m = m_{train} , m_{test} = #test examples $$ + +$$ X = [ X^{(1)} ... X^{(m)} ] is an n_x x m matrix $$ +$$ X.shape (n_x,m) $$ + +$$ Y = [ y^{(1)} ... y^{(m)} ] $$ +$$ Y.shape = (1,m) $$ + +** Logistic Regression + +Given $X \in \mathbb{R}^{n_x}$ you want $\hat{y} = P(y=1 | X)$ + +Paramters: $w \in \mathbb{R}^{n_x}, b\in \mathbb{R}$ + +Output: $\hat{y} = \sigma(w^Tx + b) = \sigma(z)$ + +$$\sigma(z)= \frac{1}{1 + e^{-z}}$$ + +If $z \rightarrow \infty => \sigma(z) \approx 1$ +If $z \rightarrow - \infty => \sigma(z) \approx 0$ + + +Alternative notation not used in this course: + +$X_0=1, x\in\mathbb{R}^{n_x+1}$ +$\hat{y} = \sigma(\Theta^Tx)$ +... + +** Logistic Regression Cost Function + +Search a convex loss function: + +$L(\hat{y},y) = - (y\log(\hat{y}) + (1-y)\log(1-\hat{y}))$ + +If y = 1 : $L(\hat{y},y) = -\log\hat{y}$ <- want log\haty larg, want \hat{y} large +If y = 0 : $L(\hat{y},y) = -\log\hat{y}$ <- want log (1-\hat{y}) large, want \hat{y} sall + +Cost function: $$ J(w,b) = \frac{1}{m}\sum_{i=1}^mL(\hat{y^\{(i)}},y^{(i)}) = ... $$ + +** Gradient Descent + +Minize $J(w,b)$ + +1. initialize w,b (generaly uses zero) +2. Take a step in the steepest descent direction +3. repeat 2 until reaching global optimum + +Repeat { + $w := w - \alpha\frac{dJ(w)}{dw} = w - \alpha\mathtext{dw}$ +} + +** Derivatives +** More Derivative Examples +** Computaion Graph +** Computing Derivatives +** Computing Derivatives for multiple examples +** Vectorization +getting rid of explicit for loops in your code +** Vectorizing Logistic Regression +** Vectorizing Logistic Regression's Gradient Computation +** Broadcasting in Python +** Quick Tour of Jupyter / ipython notebooks +** Neural Network Basics +J = a*b + a*c - (b+c) = a (b + c) - (b + c) = (a - 1) (b + c) +* TODO Improving Deep Neural Networks: Hyperparameter tuning, Regularization and Optimization +** DONE Week 1: Setting up your Machine + CLOSED: [2017-08-22 Tue 13:43] +*** Recipe + +If *High bias*? (bad training set performance?) + Then try: + - Bigger network + - Training longer + - (NN architecture search) + Else if *High variance*? (bad dev set performance?) + Then try: + - More data + - Regularization + - (NN architecture search) + +Deep learning, not much bias/variance tradeoff if we have a big amount of +computer power (bigger network) and lot of data. +*** Regularization +**** Regularization: reduce variance + - L2 regularization + + λ / 2m || w ||_2 ^2 + + - L1 regularization: same with |w| instead of ||w||_2^2 + + + λ is a regularization parameter (in code named =lambd=) + + Cost = J(w^[1], b^[1], ..., w^[L], b^[L]) = 1/m \sum L(^y(i), y(i)) + λ/2m \sum_l=1^L || W^[l] ||^2 + + + call the "Frobenius norm" + + dW = from backprop + λ/m W^l + + update W^l = W^l - αdW^l still works + + Sometime L2 regularization called "weight decay". + +**** Dropout Regularization + + Eliminates nodes by layer randomly for each training example. + + - implementing, (inverted dropout) + - gen random boolean vector: + d3 = np.random.rand(a3.shape[0], a3.shape[1]) < keep_prob # (for each iteration) + a3 = np.mulitply(a3,d3) + a3 /= keep_prob (for normalization to be certain the a3 output still the same, reduce testing problems) + + Making prediction at test time: no drop out + +**** Over regularization methods + + - Data augmentation, (flipping images for example, random crops, random distortions, etc...) + - Early stopping, stop earlier iteration + +*** Setting up your optimization problem + +**** Normalizing Inputs + + - μ = 1/m Sum X^(i) + - x := x - μ (centralize) + - σ = 1/m Sum X^(i)^2 + - x /= σ^2 + + +**** Gradient Checking +***** Don't use gard check in traingin, only in debug +***** If algorithm fail, grad check, look at component (is db? dW? dW on certain layer, etc...) +***** Remember regularization +***** Doesn't work with dropout, turn off drop out (put 1.0) then check +***** Run at random initialization; perhaps again after training + +** DONE Week 2: Optimization Algorithms + CLOSED: [2017-08-22 Tue 13:43] +*** Mini batch + + X :: X^(1) ... X^(m) + + X,Y -> X^{i},Y^{i} where X^{i} = X^(i*batch-size ---> (i+1)*batch-size) + +*** Minibatch size + +- if mini batch size = m => Batch gradient descent (X^{1},Y^{1}) = (X,Y) +- if mini match size = 1 => Stochastic gradient descent, every example is its own mini batch. +- in practice in between 1 and m, m --> too long, 1 loose speedup from vectorization. + + vectorization ~1000 + +1. If small training set, use batch gradient descent (m <= 2000) +2. Typical mini-batch size: 64, 128, 256, 512, ... 2^k to fits in CPU/GPU memory + +*** Exponentially weighted average + +v_t = βv_{t-1} + (1-β)θ_t +** TODO Week 3 +** TODO Week 4 diff --git a/Introduction/Scale%20drives%20deep%20learning%20progress_2017-08-15_08-14-39.png b/Introduction/Scale%20drives%20deep%20learning%20progress_2017-08-15_08-14-39.png new file mode 100644 index 00000000..6ba1a878 Binary files /dev/null and b/Introduction/Scale%20drives%20deep%20learning%20progress_2017-08-15_08-14-39.png differ diff --git a/Introduction/Screen%20Shot%202017-08-15%20at%2008.12.26_2017-08-15_08-12-42.png b/Introduction/Screen%20Shot%202017-08-15%20at%2008.12.26_2017-08-15_08-12-42.png new file mode 100644 index 00000000..6ba1a878 Binary files /dev/null and b/Introduction/Screen%20Shot%202017-08-15%20at%2008.12.26_2017-08-15_08-12-42.png differ diff --git a/Nicolas.org b/Nicolas.org new file mode 100644 index 00000000..cf56197c --- /dev/null +++ b/Nicolas.org @@ -0,0 +1,296 @@ +#+Title:Nicolas Meetings + +* Etude Transient +** Installation et Test +*** Node.js +Il faut avoir une version récente de node.js (j'ai la 6.5.0) +*** Cabal file +#+BEGIN_SRC cabal +build-depends: base + , transient + , transient-universe + , transformers + , ghcjs-hplay + , containers +#+END_SRC +*** stack.yaml +#+BEGIN_SRC yaml +resolver: lts-6.15 +packages: +- '.' +extra-deps: +- ghcjs-perch-0.3.3 +- transient-0.4.2 +- transient-universe-0.3.2.1 +- ghcjs-hplay-0.3.4 +flags: {} +extra-package-dbs: [] +#+END_SRC +*** stack-ghcjs.yaml +#+BEGIN_SRC yaml +resolver: lts-6.15 +packages: +- '.' +extra-deps: +- ghcjs-perch-0.3.3 +- transient-0.4.2 +- transient-universe-0.3.2.1 +- ghcjs-hplay-0.3.4 +flags: {} +extra-package-dbs: [] +# GHCJS +compiler: ghcjs-0.2.0.9006015_ghc-7.10.3 +compiler-check: match-exact +setup-info: + ghcjs: + source: + ghcjs-0.2.0.9006015_ghc-7.10.3: + url: "https://tolysz.org/ghcjs/lts-6.15-9006015.tar.gz" + sha1: 4d513006622bf428a3c983ca927837e3d14ab687 +#+END_SR +*** Compile & Start +**** Compile +#+BEGIN_SRC zsh +#!/usr/bin/env bash -x + +if command -v stack >/dev/null 2>&1 +then echo "stack is already installed." +else + echo "stack is not installed. I will try to install it." + curl -sSL https://get.haskellstack.org/ | sh +fi + +# Downloading Haskell Compiler this can be very long +stack setup +stack --stack-yaml stack-ghcjs.yaml setup + +# Building the project the first time it will also download and compile +# library +stack build +stack --stack-yaml stack-ghcjs.yaml build + +# Link GHCJS result to the correct directory (static/out.jsexe) +./mklink.sh +#+END_SRC + +**** Start + +#+BEGIN_SRC zsh +#!/usr/bin/env bash + +stack exec -- wse-exe -p start/localhost/3000 +#+END_SRC + +**** Test +1. =./compile.sh= +2. =./start.sh= +3. Aller sur =http://localhost:3000= avec plusieurs navigateurs. + +À noter des reload nécessaires avec Safari, marche très bien avec Firefox. +** Explication +*** Le Code +Voici le code suivant + +#+BEGIN_SRC haskell +import Prelude hiding(div,id) +import Transient.Base +import Transient.Move +import Transient.EVars +import Transient.Move.Utils +import GHCJS.HPlay.View hiding (option,input) +import Data.IORef +import Data.String (fromString) +import Control.Monad.IO.Class +import Data.Monoid ((<>)) +import Data.Typeable (Typeable) + +data MyForm = MyForm { i1, i2 :: String } deriving (Show,Read,Typeable) + +main :: IO () +main = keep $ do + rdata <- liftIO $ newIORef (MyForm "i1" "i2") + dataAvailable <- newEVar + initNode $ formWidget rdata dataAvailable + <|> syncWidget dataAvailable + <|> longLivingProcess rdata dataAvailable + +formWidget :: IORef MyForm -> EVar MyForm -> Cloud () +formWidget rdata dataAvailable = onBrowser $ do + local . render . rawHtml $ do + h1 "State" + div ! id (fromString "msg") $ "No message yet." + st <- atRemote . localIO $ readIORef rdata -- read the state data + myForm <- local . render $ MyForm <$> getString (Just (i1 st)) `fire` OnKeyUp + <*> getString (Just (i2 st)) `fire` OnKeyUp + -- notify the long living process + atRemote $ localIO $ writeEVar dataAvailable myForm + +syncWidget :: EVar MyForm -> Cloud () +syncWidget dataAvailable = onBrowser $ do + -- display in the browser + received <- atRemote $ local $ readEVar dataAvailable + local . render . at (fromString "#msg") Insert . rawHtml $ + p $ "Check other navigators: " <> i1 received <> ", " <> i2 received + +longLivingProcess :: IORef MyForm -> EVar MyForm -> Cloud () +longLivingProcess rdata dataAvailable = + onServer $ local $ do + liftIO $ print "longliving" + dat <- readEVar dataAvailable + liftIO $ writeIORef rdata dat + liftIO $ print $ show dat <> " arrived" +#+END_SRC + +Que se passe-t-til ? + +On voit un formulaire de deux input. Lorsque l'on modifie un champs, un message +se met à jour automatiquement et on voit que le formulaire est envoyé au serveur +lorsque l'on regarde les logs. +On remarque que tous les messages se synchronisent sur tous les navigateurs! + +*** Les widgets + +- formWidget (le formulaire) +- longLivingProcess (le process sur le serveur) +- syncWidget (le message au dessus du formulaire) + +Lorsque l'on utilise `(<|>)` celà signifie que l'on va lancer le code sur toutes +les instances de l'application (toutes les instances frontend et backend lancées). + +Mais on peut lancer des commandes seulement sur le frontend, d'autres seulement +en backend. + +**** Init +- on initialise un IORef qui joue le rôle d'une DB. +- Dans une vrai application il faudrait remplacer IORef par un système + persistant +- On initialise aussi un EVar (Event Var) donc on va envoyer des events. +**** formWidget (le formulaire) + +#+BEGIN_SRC haskell +formWidget :: IORef MyForm -> EVar MyForm -> Cloud () +formWidget rdata dataAvailable = onBrowser $ do + local . render . rawHtml $ do + h1 "State" + div ! id (fromString "msg") $ "No message yet." + st <- atRemote . localIO $ readIORef rdata -- read the state data + myForm <- local . render $ MyForm <$> getString (Just (i1 st)) `fire` OnKeyUp + <*> getString (Just (i2 st)) `fire` OnKeyUp + -- notify the long living process + atRemote $ localIO $ writeEVar dataAvailable myForm +#+END_SRC + +- le `onBrowser` au début montre bien que on ne s'exécute que sur le browser. +- le `local` signifie que l'on fait quelque chose en local sur le front +- on a un `atRemote` qui signifie que cette opération doit avoir lieu sur une + instance `remote` (le serveur) +- en remote on récupère simplement la valeur dans le IORef et on la récupère + coté front (black magic!) +- les `fire` OnKeyUp signifie que la continuation (ce qu'il y a après la ligne + courante) et relancée à chaque event keyUp. + +**** longLivingProcess (le process sur le serveur) + +#+BEGIN_SRC haskell +longLivingProcess :: IORef MyForm -> EVar MyForm -> Cloud () +longLivingProcess rdata dataAvailable = + onServer $ local $ do + liftIO $ print "longliving" + dat <- readEVar dataAvailable + liftIO $ writeIORef rdata dat + liftIO $ print $ show dat <> " arrived" +#+END_SRC + +- le `onServer` signifie bien que l'on est sur le serveur +- est le code est très simple, lorsqu'il reçoit un évênement via l'EVar, il le + sauvegarde dans l'IORef et il log la valeur reçue + +**** syncWidget (le message sous le formulaire) + +#+BEGIN_SRC haskell +syncWidget :: EVar MyForm -> Cloud () +syncWidget dataAvailable = onBrowser $ do + -- display in the browser + received <- atRemote $ local $ readEVar dataAvailable + local . render . at (fromString "#msg") Insert . rawHtml $ + p $ "Check other navigators: " <> i1 received <> ", " <> i2 received +#+END_SRC + +- le onBrowser est là pour signifier que l'on se situe sur le browser +- on "écoute" l'EVar à partir du serveur +- dans le render on écrase (via un insert JS) par du HTML maison. + +L'idée du on écoute, c'est simplement que chaque ligne du `do` sauvegarde des +continuations qui se relancent lorsque l'on fait un readEVar par exemple. + +*** Retour + +Donc après avoir joué avec cette première étape et essayer de comprendre comment +utiliser la librairie. Je dois dire que je suis plutôt impressioné. J'avais peur +de tomber sur du code "magique". Mais ça n'est pas tant le cas. + +Ce qui a l'air magique : + +- décrire au même endroit comment doit se comporter le front et le back et + comment ils interagissent. +- Communication entre process qu'ils soient dans un navigateur web ou pas + +La monade transient est certes complexe, mais la première étape est de +comprendre que la monade capture les continuations. + +En ce qui concerne l'utilsation avancé du typage. Je ne pense pas qu'il en fasse +grand usage. Il utilise juste ce qui est nécessaire pour ne pas faire bugger sa +lib. Par contre il n'est jamais demandé à l'utiliser de créer des types. + +De mon point de vue, sa monade reste très (trop?) ouverte. + +J'ai aussi constaté des bugs assez incompréhensibles, suffisamment pour avoir un +peu peur d'utiliser ça en prod. +À mon avis nous avons deux choix pour avancer: + +- soit modifier sa lib pour utiliser =Transient m= plutôt que =TransIO = + Transient IO= directement. +- Soit nous créer une Free Monade qui copie l'API de transient pour nos besoins + et dont l'un des interpréteur appelera transient. + +On peut aussi imaginer un quelque chose entre les deux. Pour ma part, je vais +discuter un peu avec Corona en ce qui concerne les bugs, le fait qu'il travaille +sous windows ne doit pas aider je présume. + +* 2016-09-05 +- Transient, MFlow +- Kmett: Monad Homomorphisms +* 2016-07-29 +** Attribute Grammar +- https://wiki.haskell.org/The_Monad.Reader/Issue4/Why_Attribute_Grammars_Matter +- AST → AST +- Repmin: un seul parcours d'arbre +- Transducer de DAG +- Patrick Bahr +- Composing & Decomposing Data Types (Patrick Bahr) +** TODO +- pl-cli demo (avec la liste des constructors) +- pl-server +* 2016-07-11 +** List value constructors from a types + +~~~~ +ghci> :m +Data.Data +ghci> let x = toConstr (Just False) +ghci> constrType x +DataType {tycon = "Prelude.Maybe", datarep = AlgRep [Nothing,Just]} +~~~~ + +~~~ +Prelude Data.Data> :set -XDeriveDataTypeable +Prelude Data.Data> data Cmd = X | Foo Int | Bar Bool deriving (Data) +Prelude Data.Data> let y = toConstr X +Prelude Data.Data> constrType y +DataType {tycon = "Cmd", datarep = AlgRep [X,Foo,Bar]} +~~~ + +import ... (Cmd(..)) + +- Cmd ???? +- Cmd => [X,Foo,Bar] ???? +- Foo => Foo :: Int -> Cmd ???? diff --git a/TODO.org b/TODO.org new file mode 100644 index 00000000..ceea2d58 --- /dev/null +++ b/TODO.org @@ -0,0 +1,65 @@ +#+Title:TODO +#+Author: Yann Esposito +#+TODO: TODO IN-PROGRESS WAITING | DONE CANCELED +#+COLUMNS: %TODO %3PRIORITY %40ITEM(Task) %17Effort(Estimated Effort){:} %CLOCKSUM %8TAGS(TAG) + + +* TODO [#C] FP Meetup :geek: + DEADLINE: <2017-10-30 Mon> +** DONE Presentation History of FP, etc... + CLOSED: [2017-06-21 Wed 08:09] +* TODO [#C] Reddit Bot with GUI :geek: +** TODO [#C] Configuration Form :ps: + :PROPERTIES: + :EFFORT: 4:00 + :END: +#+BEGIN_SRC purescript +type UserConf = UserConf + { subreddit :: Text + , regex :: Regex + , reply :: Text + , enabled :: Bool + } +data Stored a = Stored { id :: ID, stored :: a } +#+END_SRC +** TODO [#C] Bot listen to HTTP Calls :hs: + :PROPERTIES: + :EFFORT: 4:00 + :END: +*** TODO =POST /conf= create new conf +- body params subreddit, regex, reply +*** TODO =PUT /conf= update conf +- body params subreddit, regex, reply +*** TODO =GET /confs= retrieve all confs (can filter on subreddit) +- query params subreddit +*** TODO =DELETE /conf/conf= +** TODO [#C] User Auth :hs: + :PROPERTIES: + :EFFORT: 16:00 + :END: +** TODO [#C] Install and let it run on shoggoth1 :ops: + :PROPERTIES: + :EFFORT: 2:00 + :END: +* DONE Impots :admin: + CLOSED: [2017-06-21 Wed 07:53] +** DONE Vérifier Revenu Cisco 2016-12: 52407€ + CLOSED: [2017-05-17 Wed 21:43] +** DONE Vérifier décalaration revenus auto-entrepreneur + CLOSED: [2017-04-19 Wed 12:24] +** (ABC-Cours) 1794 + (O2) 931.19 = 2725 +** Frascati +*** Intérêts d'emprunts: 7193,9 +*** Où déclarer le max - garage? +** DONE Cases Réduction Duflot + CLOSED: [2017-05-17 Wed 21:43] +* DONE Anniv K :family: + CLOSED: [2017-05-02 Tue 13:55] +** Nous (4 adultes) +** Audrey (2 + 1 enfant) +** Caro (2 adultes + 1 enfant) +** Renée (1 adulte) +** Laurent (1 adulte) +** Sonia (1 adulte ou 1 adulte et deux enfant, ou 2 adultes et 4 enfants) +** Guillaume & Emilie (2 adultes et 1 enfant) +** TOTAL Adultes: 14 adultes + 5 enfants. diff --git a/blog-FP-Survey.org b/blog-FP-Survey.org new file mode 100644 index 00000000..7c425119 --- /dev/null +++ b/blog-FP-Survey.org @@ -0,0 +1,213 @@ +#+Title: Functional Programming Survey + +* Intro (Definition / History) +** FP definition +*** Programming paradigm +*** Avoids changing-state and mutable data +*** Declarative programming, expression or declarations instead of statements +*** Output value of a function depends *only* on the arguments that are input to the function +*** Eliminating side-effects, easier to reason about code and predict behavior +*** Functions are *first-class* +which means that they are treated like any other values and can be passed as arguments to other functions or be returnred as a result of a function. +** History +*** λ-Calculus, Alonzo Church & Rosser 1936 +Typeless theory of functions. + +A syntaxic construction can be equivalent to any Turing Machine. +Mainly re-writing rules. +**** Learn λ-Calculus in less than 1 minute +***** Definitions +- =a,b,...= are variables +- =()= parenthesis to group part of an expression +- =λ= greek letter (pronounced Lambda) and the =.= to write functions. +***** Free vs Bound +- =λx.xy= the expression is open as =xy= contains a =y= and there is no =λy= that bound it. +- =λx.λy.xy= is said to be bound. + +Bound expressions represent functions. + +***** Rules + +(α) λx.A → λy.[y/x]A +(β) (λx.A)B → λy.[B/x]A +(η) λx.Ax → A if x not free in A + +Where =[B/x]A= means substitue B for free occurrences of x in A. + +***** How does that work? Simply cut and paste! That's it + +Example: =(λy.x(yz))(ab)= + +So =(ab)= is an expression we apply to the function =(λy.x(yz))=. +So replace =y= by =ab= and we get: =x(abz)=. + +And... + +That's it. + +*** LISP (McCarthy 1960) +The first functional programming language and the second oldest programming +language stil in use (after FORTRAN). + +**** S-Language +- atom which are words like X or TWO +- pairing operation written as a dot + +=((X.Y).Z)= +=(ONE.(TWO.(THREE.NIL)))= + +List, Trees, etc.. + +**** M-Language +defines computations on S-exrepssions. It has +- S-expressions +- function application (=f[a;b;...]=) with primitve functions =cons=, =car=, =cdr=, =atom=, =eq= +- conditional expressions (=[ test1 -> result1 ; test2 -> result2 ; ... ]=) +- ability to define recursive functions (=first[x] = [atom [x] -> x ; T -> first[car[x]]]=) + +**** Encoding M-Language expressions and functions as S-Expressions +define M-language functions =eval= and =apply= that correctly interpret these S-expressions + +Thus LISP allow meta-programming: treating program as data and vice versa + +**** LISP Syntax so much parenthesis + +It was intended to code use M-language in an Algol-like notation. +In practice LISP wrote their code directly in S-expressions. +M-language became a kind of ghost... theoretically important but not used by anyone. + +*** Algol 60 (Naur et al 1963) +*** ISWIM (Landin 1966) +*** PAL (Evans 1968) +*** SASL (1973-83) +*** Edinburgh (1969-80) -- NPL, early ML, HOPE +- NLP strongly typed but no polymorphisms, call-by-value +- NLP evolved into HOPE: higher order, strongly typed with explicit types and + polymorphic type variables, purely functional. +- ML (Meta-Language) emerged as the meta-language of Edinburgh LCF, programmable verification system +- Standard ML (Milner et al. 1990) pattern matching and type inference but _not pure_. +*** Miranda (1986) +- Milner type discipline: ~tree * :: Leaf * | Node (tree *) (tree *)~ +- Use of =*=, =**=, =***=, ... syntax as type variables from original ML +*** Haskell (1992...) +Similar to Miranda but richer and more redundant syntax. ++ type classes ++ monadic IO ++ module system + +* Major Principles (Theoretical) +** Higher-order functions +** Purity +*** Function vs Procedure/Subroutines +**** Referential Transparency vs Referential Opacity +- Ability to copy/paste without changing result vs impossible +- Help the programmer but also the compiler! +- Help in proving correctness +- Help simplifying algorithms, better linters +- Optimizing by memoization, common subexpression elimination, lazy evaluation, parallelization +**** Parallel computation become extremely easier to achieve +***** Evaluation strategies: +****** =(h (f a) (g b))= We can evaluate: =a= then =(f a)= then =b= then =(g b)= and finally =(h (f a) (g b))= +****** =(h (f a) (g b))= We can evaluate: =b= then =a= then =(g b)= then =(f a)= and finally =(h (f a) (g b))= +****** =(h (f a) (g b))= We can evaluate: =a= and =b= in parallel then =(f a)= and =(g b)= in parallel and finally =(h (f a) (g b))= +****** =(h (f a) (g b))= We can evaluate: =h= and then evaluate =(f a)= only if needed and then =(g b)= only if needed... + That's called non-strict evaluation (sometime lazy evaluation) +For example if: =(def h (λx.λy.(+ x x)))= we don't need to evaluate =y=, in our case =(g b)= +**** Time is Hard, purity remove time from the paradigm +Calling the same function with the same parameter twice will always results in the same value. +*** Effects? +**** Side effects in the language +The programmer must be careful not to use impure functions in place where only pure functions are expected. +**** Split impurity using a flag (generaly a type) +- =foo : Int -> String= declared as pure +- =foo : Int -> IO String= declared as impure (IO) +*** Exceptions / Errors? +We can't avoid the fact real world has limits! Space limit, maybe time limit, +maybe access limitations... +** Tail Recursion +Recursion is heavily used in functional programming. Functional language will +often include *tail call optimisation* to ensure that heavy recursion does not +consume excessive memory. +** Functional Programming Style and Grey area Languages + +Functional Style can be achieved in most languages. For example in Perl, PHP, +C++11, Java 8 and C# 3.0. all added features to facilitate the functional style. + +Scala is special as it is frequently written in a functional style but the +presence of side effects and mutable state place it in a grey area. + +*** A Hole in purity, and all great properties of functional programming fall appart + +This is a major point. You cannot compromise with purity without losing +everything. Extremely well explained in the SICP when he introduce the =set!= +ability to *mutate* the value associated to a variable. + +*** Grey Area Languages +**** XSLT +**** R, J, K and Q +**** SQL (declarative) +**** Lex/Yacc a bit + +** Meta-Programming and Macros! + +If you really want to have the next power level, you can write macros, or what +is mostly called meta-programming. + +A notable thing to know about are LISP Macros. + +** Type System +First, If when I say static typing you think C, C++, Java... No, that's NOT THAT AT ALL! + +Type Theory is a vast mathematical field, with lot of hard and incredible work. + +Some language don't need type system at all. Typically most LISP are very close to a raw lambda calculus. + +But there is a problem with untyped languages: ⊥ + +Even we provided purity, you can imagine a system that help you reason about +your code even further by adding more meta informations. + +Different type systems: Hindley Milner, Martin/Lof, HoTT + +- Basic Types (same as in Java) +- Parametric Types ⇒ many different polymorphisms to choose +- ADT! ⇒ Algebraic Data Types (type with algebraic properties FTW!) +- GADT! ⇒ Generalized Algebraic Data Types +- Generic Programming (be able to understand that two data structure share the same underlying structure) +- Typeclasses ⇒ Incredible ability to abstraction (Monoids, Functor, Applicative, Monads, Traversables...) + +* Major Languages (Practical) + +- We only talk about General purpose languages (not domain specific languages) +- Prod ready or not is only regarding our current knowledge. And by prod ready + it won't be enough to name less than 5 company using it for small project. +- Prod ready mean used at 100% by a company earning money for some years, and + used partially (more than 10%) by more than 10 company or having a big + production project + +** Not Pure +*** Can be used in modern production env +**** LISP Family +***** Common Lisp +***** Clojure (Generally pure as default data structure are pure) +**** Not LISP & General Purpose Languages +***** Erlang +***** Mathematica +***** OCaml +***** F# +*** Not suitable for production yet +**** LISP Family +***** Scheme +***** Racket +**** Not LISP, General Purpose Languages +***** Erlang +***** ML, Caml +** Pure +*** Prod ready +**** Haskell +**** Elm +*** Not Prod ready yet +**** Idris +**** Frege +**** Eta (Haskell 7.10 on the JVM) might be used in production but really recent +**** Clean diff --git a/blog-false-programmer-problems.org b/blog-false-programmer-problems.org new file mode 100644 index 00000000..d4f80ed1 --- /dev/null +++ b/blog-false-programmer-problems.org @@ -0,0 +1,94 @@ +#+Title:Dev problem that don't help progress + +There are a lot of debates between devs. Some of them are useful because after +some time some clear winner emerge. But some are just a matter of either +personal preferences, or even worse, won't change the outcome. + +Why such debate continu to live years after years is just a matter of friction. +Because my personal choices influence yours. For example, if I chose to use some +editor code style by using spaces and you prefer to use tabs. We have a problem, +and as each one of us want to keeps its habits, we might try to rationalize our +choices. While really it is just a matter of personal preference. And so, in the +end we should decide which one win. + +So if you don't want to lose your time by searching to optimize your life here +are the conclusions before the debate. + +* Trivial Debates +** Tools & Habits +*** vim vs emacs vs any editor +matter of personal preferences, I switched to vim keybinding mostly to prevent +hand problems, and text editing might be slighly faster at the cost of a long +training +*** font choice +**** Edit code +Simply chose a monospaced font that make a clear distinction between: + +- `0` and `O` +- `1` and `l` +- ``` and `'` +- `''` and `"` +- `1` and `i` +- `8`, `B`, `6` and `0` +- `2` and `Z` +- `5` and `S` +- `|` and `!` +- `()` and `{}` +- `:`, `;` and `i` +- `.` and `,` + +**** Website design + +If you're not a designer don't over think about it. +Just chose one preferred Sans serif and Serif font. + +*** color scheme choice +You should really use a low contrast colortheme if you want to minimize +headhache and there are good chances you'll end up preferring dark themes. + +*** tabs vs spaces +Spaces appear to win slightly because the file size is not really important and +most people don't care. + +Smart tabs have still some issues with alignment. + +*** OS choice for working +Matter of personal preference + +*** Typed (static) vs Unityped (dynamic) programming language +I've got a long answer here, but if you are a proponent to unityped programming +(dynamic typed programming) then you might not know language with great typing +system. + +If you are a proponent to static typing programming then know you can live using +unityped programming. + +The long answer being. Types are another abstraction. So as all abstraction, it +has some benefits and some costs. I tend to believe that once you have finished +your Proof of Concept Prototype, Types provide a lot more benefits than +drawbacks. You can think about them as free unit testing. In fact with a complex +enough type system you can think about them as an infinite number of unit tests +for free. But just know that event with advanced typing system doesn't prevent +you to write tests. But the opposite is also false, you can't simulate easily a +typing system with only tests, even generative testing. + +* My Choices +** editor: spacemacs (best of vim and emacs) +** font choice: Menlo (on OS X, Hack on other OS) +** color scheme: solarized dark (each time I try to change I came back to it) +** tabs vs spaces: spaces (no configuration pb, file size doesn't matter today) +** Mac OS X: best for working, better focus, minimal configuration, setup time (would love a \*Nix env) +** configurations/dotfiles: yadm +** CVS: git with github (it's a social network) +** typed vs untyped: typed help think right, but untyped is not _that_ bad. +** Todo list, timers, note taking, thought orgnaiser: `org-mode` + +* Solved but not known enough +** REST (not RESTful) +- Why REST: least surprise + +** Encoding +- Use UTF-8 Everywhere + +** Readability: +- lenght of line (33em) diff --git a/blog-on-SCRUM.org b/blog-on-SCRUM.org new file mode 100644 index 00000000..aa392443 --- /dev/null +++ b/blog-on-SCRUM.org @@ -0,0 +1,62 @@ +#+Title:On Scrumm + +It is of good taste these day to critique Scrumm. +Here are my 2cents + +* Personal Experience with Scrum: +** Discovering +- Fear and counter arguments +** Efficiency +- Time lost in meeting +** People tensions +- instead of tamming it made everything worse. +* Management: The root of all evil? +The root of the problem is between the developpers and the managers. +- Manager: I want a great product, I want to finish it fast, I want my customers to love it +- Developer: I want a great product, I want to finish it fast, I want customers to love it + +What could go wrong? + +- What Manager means: _I want a great product_: + I want to sell it! +- What Developer means: _I want a great product_: + I want it to use the last technology, with the last code organization/quality trends + +- Manager: _I want to finish it fast_: + I don't want to listen to technical discussion, + this looks like something easy to do. + It should be in my hand in few weeks. +- Developer: _I want to finish it fast_: + I want to keep the code clean to be able to add new changes fast + with confidence (without breaking anything) + this certainly means, testing + testing environment + proofs ... + +- Manager: _I want customer to love it_: + They should buy more and more. The product should be useful. +- Developer: _I want customer to love it_: + User should enjoy using it. The product should be simple, clean, natural, beautiful. + +The two meaning are'nt completely opposite. +Still they are quite different. + +* What could we do about it? + +How to solve the problem? +- Spoiler: _you can't_. + +The root of all evil is "it looks easy, do it". +Proof, a guy made the same thing in PHP in 2003, or I saw the same shit in Flash around 1998. + +You have two choices: + +1. Use tools to finish your work fast, but the cost is very to maintain and modify. +2. Use tools that enforce quality, you'll have a starting cost. + +Error not to do: +- Manager ask for something, you use your l337 H4X0R cape and you show him + something in less than 10 minutes. +- Manager believe that everything should be as fast +- Discover what you did was just a terrible hack, and take 2 days to finish it + correctly. +- Manager doesn't really understand why he _saw_ it right now, and has to wait + many days to really have it in production. diff --git a/blog-programming-choices.org b/blog-programming-choices.org new file mode 100644 index 00000000..47a738e9 --- /dev/null +++ b/blog-programming-choices.org @@ -0,0 +1,69 @@ +#+Title: Programming experiences and choices +#+Author: Yann Esposito +#+Language: English +#+Select_tags: Programming, culture + +* TODO Introduction + +Why each programmer tend to prefer some programming language to solve its problems. +How are we creating our preferrences? +Why one use vim and the other one can use a specialized IDE? + +* Preferences depends on experiences +** Hard to understand +** Goals +* Back Story +** At first + +- Logo when I was 10yo at school +- Basic when I was 11yo, with a book trying to draw lines and make games +- Basic with Amtrad CPC 6128, trying to write games from magasines +- Compiled Basic with Atari STe, write a game you are the hero in it. +- Take some courses of beginner Pascal at school, sort algorithms +** Math Background then Computer Science + - Pascal for algorithmic + - C, for basics, system and network + - C++, Eiffel for Object Oriented Programming + - A little bit of CaML (write a mathematical expression simplifier making big + usage of pattern matching) +** Ph. D. In Machine Learning +- Give courses of Logo, C, etc... +- Write lot of complex HMM related algorithms in C++ with quite complex ML algorithms +- Discover Java and its promises, play a bit with it +- Have friend that use CaML for its Ph.D. and its hash-maps are said to be + faster than C. I remember this. +** No Love for Machine Learning in 2005 :/ +- Write a Java program with an User Interface in my Post Ph. D. 1/2 of the work + in the UI, the other half in the algorithm. +** Still no love for ML in 2006 Find a job just to eat +- Go find a job to eat, have a *lot* of time to learn new things +- Discover HN, /r/programming, etc... +- Web Applications are all the rage +- DCVS is still a thing, people argue between git, mercurial, bazaar, etc... +- Write a tremendous number of zsh scripts to handle a huge number of files, use Perl, etc... +** First try at startup + - Decide with a friend to make a product, choice of technology with them is _very_ hard. + - git for example was a question + - using FB connect instead of classical, name / password bullshit is refused + because they still live technically in 2000 + - Design decisions are hard to make + - Programming language, I heard good things about OCaML as the fastest high + level language. Can't even talk about it. + - A guy need technicians to make its product and is willing to pay. + - OK good first thing to try ourselves. + - The other guy know Ruby, so let's go with Ruby (no rails) + - Write our own framework, many technical frictions, but in the end a PoC is + made full ruby, deployed on heroku. The product is an end-to-end personal + electrical power consumption system. + - Guy explain, I want "real time"!!!! ???? WTFBBQ!! Real time is way harder than + just drawing dashboards!!!! + - Have performance problems! Start looking into other frameworks, stumble upon + snap, an Haskell framework stating that it is _very_ fast. + - Start looking further into Haskell from there. +** Haskell learning +- Learn Haskell from web programming perspective, the goal is not to _learn_ + Haskell but to _use_ Haskell to write as fast as possible a web application + with batteries included. After trying a bit, I choose to use Yesod. +- Lot of time lost due to Yesod difficulties to handle correct package version coherence!!!! +- cabal freeze, etc... to the rescue, not perfect but ok, able to deploy on heroku +- Learn Haskell in the process. diff --git a/blog-raw-haskell-web-app.org b/blog-raw-haskell-web-app.org new file mode 100644 index 00000000..4078e22a --- /dev/null +++ b/blog-raw-haskell-web-app.org @@ -0,0 +1,504 @@ +#+Title: Haskell Web Application from scratch +#+Author: Yann Esposito + +* Introduction + +** Functional Programming oriented to make a web application + +** Tooling choices + +- macOS Sierra +- spacemacs +- stack (not using ghc-8.0.1, there is a bug with macOS) + +** High quality application + +Even if an application only print "hello world" there are a lot of subtle way +such an app could fail or have problems. See for example the [changelogs to GNU +Hello](https://github.com/avar/gnu-hello/blob/master/ChangeLog). + +The goal of this tutorial is not to provide a "see what we can do with Haskell" +but more, how could we enforce production quality development with Haskell. +Unfortunately, the tooling is very important in these matters. + +To reach such goal we should at least provide: + +- Documentation +- Unit Tests +- Generative Tests +- Benchmarks +- Profiling +- CI +- Deployment + +It's easy to have one tutorial for each of these concepts, here that won't be a +deep dive, but a first introduction on how to achieve all these goals. + +* Tooling and preparing to code + +blog-image("stillsuit.jpg","Stillsuit") + +** Warning + +If you never installed Haskell before, it should be a bit long to setup a +correct working environment. So please follow me, don't give up because +something doesn't work the first time. I made my best to make my environment +work for most people. + +** Installing Haskell Compiler + +Install Haskell etc... In my opinion the easiest way to start is to install =stack=. +Then you need to choose a great name for your project, why not =shai-hulud=? + +blog-image("shai-hulud.jpg","Shai Hulud") + +#+BEGIN_SRC bash +> stack new shai-hulud tasty-travis +#+END_SRC + +Yeah now you have a new directory, let use git: + +#+BEGIN_SRC bash +> cd shai-hulud +> git init . +#+END_SRC + +Now we have some source code, let's try it[^1]. + +[^1]: If you are on a Mac, please, modify the line =resolver: lts-7.18= by +=resolver: nightly-2017-01-25= to be certain to use =ghc-8.0.2= because there is +a bug with =ghc-8.0.1=. + +#+BEGIN_SRC bash +> stack setup && stack build && stack exec -- shai-hulud-exe +42 +#+END_SRC + +** Dependencies & Libraries + +As we want to make a web application let's add the needed dependencies to help +us. Typically we want a web server +[warp](https://hackage.haskell.org/package/warp) and also a Web Application +Interface [WAI](https://hackage.haskell.org/package/wai). We'll also need to use +[http-types](https://hackage.haskell.org/package/http-types). + +In the =shai-hulud.cabal= file, in the =shai-hulud-exe= section, add to the +build-depends =http-types=, =wai= and =warp= like this: + +#+BEGIN_SRC +executable shai-hulud-exe + default-language: Haskell2010 + ghc-options: -Wall -Werror -O2 -threaded -rtsopts -with-rtsopts=-N + hs-source-dirs: src-exe + main-is: Main.hs + build-depends: base >= 4.8 && < 5 + , shai-hulud + , http-types + , wai + , warp +#+END_SRC + +Then we modify the =src-exe/Main.hs= file to contains: + +#+BEGIN_SRC haskell +{-# LANGUAGE OverloadedStrings #-} +import Network.Wai +import Network.HTTP.Types +import Network.Wai.Handler.Warp (run) + +app :: Application +app _ respond = do + putStrLn "I've done some IO here" + respond $ responseLBS status200 [("Content-Type","text/plain")] "Hello, Web!" + +main :: IO () +main = do + putStrLn "http://localhost:8080/" + run 8080 app +#+END_SRC + +We'll go in detail later about what everything means. + +#+BEGIN_SRC bash +> stack build && stack exec -- shai-hulud-exe +... +... Lot of building logs there +... +http://localhost:8080/ +#+END_SRC + +Yeah! It appears to work, now let's try it by going on +in a web browser. You should see =Hello, Web!= in your browser and each time you +reload the page a new message is printed in the console because some IO were performed. + +** So can we start yet? + +Hmmm no sorry, not yet. + + +We should not use the default prelude. + +While this article is a tutorial, it is not exactly a "very basic" one. I mean, +once finished the environment would be good enough for production. There will be +tests, ability to reproduce the build on a CI, and so, for such a program I +should prevent it to have runtime errors. + +In fact, certainly one of the main reason to use Haskell is that it helps +prevent runtime errors. + +In order to do that we'll use a prelude that doesn't contain any partial +functions. So I choosed to use =protolude=[^2]. + + +For that that's quite easy, simply add =protolude= as a dependency to your cabal file. +We'll modify the cabal file that way: + +#+BEGIN_SRC +library + default-language: Haskell2010 + ghc-options: -Wall -Werror -O2 + hs-source-dirs: src + exposed-modules: {-# higlight #-}Lib{-# /highlight #-} + , ShaiHulud.App + build-depends: base >= 4.8 && < 5 + , http-types + , protolude + , wai + +executable shai-hulud-exe + default-language: Haskell2010 + ghc-options: -Wall -Werror -O2 -threaded -rtsopts -with-rtsopts=-N + hs-source-dirs: src-exe + main-is: Main.hs + build-depends: shai-hulud + , base >= 4.8 && < 5 + , http-types + , protolude + , wai + , warp +#+END_SRC + +We move the =app= declaration in =src/ShaiHulud/App.hs=: + +#+BEGIN_SRC haskell +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} + +module ShaiHulud.App + ( app ) +where + +import Protolude + +import Network.Wai +import Network.HTTP.Types + +app :: Application +app _ respond = do + putText "I've done some IO here" + respond $ responseLBS status200 [("Content-Type","text/plain")] "Hello, Web!" +#+END_SRC + +And we remove it from =src-exe/Main.hs=: + +#+BEGIN_SRC haskell +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +import Protolude + +import Network.Wai.Handler.Warp (run) + +import ShaiHulud.App (app) + +main :: IO () +main = do + putText "http://localhost:8080/" + run 8080 app +#+END_SRC + +So now the tooling around being able to start working seems done. + +** Not yet + +Yes I talked about: +- Installation with =stack= that should take care of installing Haskell +- How to add dependencies by adding them to the cabal file +- Sane prelude with =protolude= +- Provided an overview of WAI Application type + +But I forgot to mention part of the tooling that is generally very personal. +I use spacemacs and to take advantages of many of the editor niceties +I also use =intero= and =haddock=. + +So other things to think about: + +- Install =intero= with =stack install intero=. +- Also generate hoogle documentation: =stack hoogle data= +- You could also check the tests and benchmark suites: =stack test= and =stack bench= + +** So we should be done with prelimiaries + +So we should be done with preliminaries, at least, I hope so... + +If you started from scratch it was certainly a terrible first experience. But +be assured that once done, most of the step you've taken won't be needed for your next +project. + +* Web Application + +So what is a web application? + +** WAI + +So if you look again at the code you see that your application main function +simply print =http://localhost:8080/= and then run the server on the port =8080= +using =app=. + +The type of =app= is =Application=, if we look at the type of Application in +WAI, for example by using =SPC-h-h= on the Application keyword or by going in +the [WAI documentation](https://www.stackage.org/haddock/lts-7.18/wai-3.2.1.1/Network-Wai.html). + +We see that: + +#+BEGIN_SRC haskell +type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived +#+END_SRC + +Hmmmm.... What? So just remakr WAI is at it's third major version. So if we just +take a look at WAI in its previous version we see that Application was defined +as: + +#+BEGIN_SRC haskell +type Application = Request -> IO Response +#+END_SRC + +Which look quite more intuitive. Because, what is the role of a web server if +not sending response to requests? The IO here is just there to explain that in +order to send a response the server might use IOs like reading in some DB or the +file system. + +So why let's take a bit to analyze the new definition of =Application= in WAI 3. + +#+BEGIN_SRC haskell +type Application = Request -> (Response -> IO ResponseReceived) -> IO ResponseReceived +#+END_SRC + +It is explained: + +#+BEGIN_QUOTE +The WAI application. + +Note that, since WAI 3.0, this type is structured in continuation passing style +to allow for proper safe resource handling. This was handled in the past via +other means (e.g., ResourceT). As a demonstration: + +#+BEGIN_SRC haskell +app :: Application +app req respond = bracket_ + (putStrLn "Allocating scarce resource") + (putStrLn "Cleaning up") + (respond $ responseLBS status200 [] "Hello World") +#+END_SRC + +#+END_QUOTE + +Great, so before it was difficult to handling some resources, now it appears to +be easier to write using =bracket_=. Hmm... =bracket_=? What is this function? +If you search it in [hoogle](https://www.haskell.org/hoogle/?hoogle=bracket_): + +OK that's quite easy, you see it is a function of =Control.Exception.Base= that +we could use like this: + +#+BEGIN_SRC haskell +bracket + (openFile "filename" ReadMode) + (hClose) + (\fileHandle -> do { ... }) +#+END_SRC + +And =bracket_= is a variation of =bracket= which doesn't need the return value +of the first computation to be used the the "closing" computation. +(More details here)[http://hackage.haskell.org/package/base-4.9.1.0/docs/Control-Exception-Base.html#v:bracket_]. + +So ok, an =Application= is "mostly" a function that take a =Request= an returns +an =IO Response=. + +Good, now let's take another look to the =app= code: + +#+BEGIN_SRC haskell +app :: Application +app _ respond = do + putText "I've done some IO here" + respond $ responseLBS status200 [("Content-Type","text/plain")] "Hello, Web!" +#+END_SRC + +As you see we don't use the first parameter, the =Request=. So we could ask for +some JSON data on =/foo/bar/= with a POST, it will still respond an HTTP 200 +with content-type plain text containing the body =Hello, Web!=. + +So what a web app should provide. And here we could go down the rabbit hole of +the HTTP standard and all its subtleties. But the first thing to come in mind is +"how to handle routing"? + +One of the advantage of using a language with some types flexibility is to use +the types as a high level specification. + +** Routing + +#+BEGIN_SRC haskell +data ShaiHuludApp = Routes -> Application +#+END_SRC + +That's easy, provided a "Routes" representation we should be able to "generate" +a WAI Application. Now how should we represent a set of =Routes=? + +We should split them by: + +- HTTP Verb: =GET=, =POST=, =PUT=, =DELETE=, =HEAD=, =OPTIONS=, ... +- Path: =/=, =/users/:userID= ... +- Content-Type: =application/json=, =text/plain=, =text/html=, =text/css=, + =application/javascript=... + +Hmmm.... + +So it is immediately very difficult. And these are just the basic requirement, +what about all subtelties about Standardized Headers (CORS, ETags, ...), Custom +Headers... + +** Is that FP compatible? + +As a functional programmer, and more generally as a scientis, math lover I +immediately dislike that profusion of details with a lot of ambiguities. + +For example, REST is still ambiguous, should you use POST / PUT to update? +Should you put a parameter in: +- part of the path like =/user/foo= +- in the query param of the URI =/user?userID=foo= +- in the body? Then what parser should we use? FORM param, JSON, XML? +- in the headers? +- Why not as an anchor? =/user#foo +- How should I provide a parameter that is a list? A set? A Hash-map? Something more complex? + +The problem of web programming come from the tooling. Browsers and HTTP evolved +together and some feature existed in browser before people had really the time +to think corectly about them. + +That's called real-life-production-world. And it sucks! For a better critique of +web standards you should really read [the chapter «A Long digression into how +standards are made» in Dive into +HTML5](http://diveintohtml5.info/past.html#history-of-the-img-element). + +So how could we get back our laws, our composability? Our maths and proofs? + +We have a lot of choices, but unfortunately, all the tooling evolved around the +existing standards. So for example, using GET will be cached correctly while +POST won't. And a lot of these details. + +*** FP Compatible Web Programming? + +Let's re-invent web programming with all we know today. + +First, one recent trends has changed a lot of things. +Now a web application is splitted between a frontend and backend development. + +The frontend development is about writing a complete application in a browser. +Not just a webpage. The difference between the two notions is blurred. + +Once consequence is that now, backend application should only present Web API +and should never send rendering informations. Only datas. So this is a +simplification, the backend should simply expose "procedures", the only things +to think about are the size of the parameter to send and the size of the +response. As every of these objects will go through the wire. + +But there are interresting rules: + +- =GET= for read only functions +- =POST= generic read/write functions +- =PUT= idempotent read/write functions +- =DELETE= like =PUT= but can delete things + +But there are also HTTP code with so many different semantics. + +- =1xx=: technical detail +- =2xx=: Successful +- =3xx=: Redirection +- =4xx=: Client Error +- =5xx=: Server Error + +So there are some similarities with the HTTP 1.1 reference and the control on +functions we try to achieve with Haskell. + +One thing I'd like to imagine is simply that a Web API should simply be like a +library. We could simplify everything _a lot_ by removig most accidental +complexity. + +If we consider a web application to be split between a frontend application and +a backend application it changes a lot of things. For example, we could mostly +get rid of urls, we can consider to use the backend as a way to expose +procedures. + +Let's for example decide to use only POST, and send parameters only in the body. + +In Haskell we could write: + +#+BEGIN_SRC haskell +foo :: IO X -- ⇒ POST on /foo +bar :: A -> IO X -- ⇒ POST on /foo with a body containing an A +#+END_SRC + +And that's it. + +* Appendix +** Haskell Fragmentation vs Di + +There are many other prelude, one of my personal problem with Haskell is fragmentation. + +Someone could see "diversity" another one "fragmentation". + +Diversity is perceived as positive while fragmentation isn't. + +So is diversity imply necessarily fragmentation? +Could we cure fragmentation by making it hard for people to compete? + +I don't think so. I believe we could have the best of both world. + +Then fragmentation occurs. And fragmentation is bad, because if you have an +issue with your choice, the number of people that could help you is by nature +reduced. + +I would say that there is fragmentation when there is no one obvious choice. But +having an obvious choice for a library for example doesn't really prevent +diversity. Fragmentation: + + - NixOS, raw cabal + Linux, stack + - preludes + - editor + - stream library + - orientation of the language "entreprisy ready, production oriented" make + it work being dirty, add dirty choices for research people working in the + language, "research oriented" make it beautiful or don't make it, block + entreprisy people. + +** =bracket_= + +[^3]: Also if you are +curious and look at its implementation it's quite short and at least for me, +easy to inuit. + +#+BEGIN_SRC haskell +bracket :: IO a -- ^ computation to run first (\"acquire resource\") + -> (a -> IO b) -- ^ computation to run last (\"release resource\") + -> (a -> IO c) -- ^ computation to run in-between + -> IO c -- returns the value from the in-between computation +bracket before after thing = + mask $ \restore -> do + a <- before + r <- restore (thing a) `onException` after a + _ <- after a + return r + +bracket_ :: IO a -> IO b -> IO c -> IO c +bracket_ before after thing = bracket before (const after) (const thing) +#+END_SRC + +Very nice diff --git a/blog-transient.org b/blog-transient.org new file mode 100644 index 00000000..f64c2099 --- /dev/null +++ b/blog-transient.org @@ -0,0 +1,185 @@ +#+Title: Haskell Transient + +* Transient Basic +** Basic operators =async= and =(<|>)= + +#+BEGIN_SRC haskell +import Control.Monad.IO.Class (liftIO) +import Transient.Base (keep',async) +import Transient.Move (local,onAll,runAt,lliftIO,Node,Cloud,addNodes,listen,createNode,runCloudIO) +import Data.Monoid ((<>)) +import Control.Applicative ((<|>),empty) +import Data.Foldable (traverse_) +flapping :: IO () +flapping = keep' $ do -- keep' is just here to stranslate from TransIO to IO + -- Inside this do we are in the TransIO Monad context + x <- async (return "1") -- spawn another thread + <|> async (return "2") -- spawn another thread + <|> return "main thread MUST BE AT THE END!!!!!!" -- don't spawn any thread + liftIO $ print x +#+END_SRC + +So this code spawn 2 threads, each printing something different. The first will +print ="1"=, the second ="2"= and the main thread will print ="main thread MUST +BE AT THE END!!!!!!!"=. + +*** Intuition for =(<|>)= + +=(<|>)= is an operator of choice on Applicative. +To shut down all the abstraction bullshit. +Let's just say that =(<|>)= operator is defined aside of an =empty= element. +Just that: + +#+BEGIN_SRC +empty <|> x = x +x <|> empty = x +#+END_SRC + +In TransIO monad context, it will choose the first non empty choice. + +#+BEGIN_SRC haskell +> Just "Hello" <|> Just "World" +Just "Hello" + +> Nothing <|> Just "World" +Just World + +> :t (<|>) +(<|>) :: Alternative f => f a -> f a -> f a + +-- Compare to this: +> :t (<*>) +(<*>) :: Applicative f => f (a -> b) -> f a -> f b + +> (,) <$> Just "Hello" <*> Just "World" +Just ("Hello","World") + +> (,) <$> Nothing <*> Just "World" +Nothing +#+END_SRC + +*** Follow up + +In the code example as =async= will return empty in the current process but not +empty in the other process. The same code do two different things depending on +the context. Exactly like =fork= in =C=. + +* Working with multiple nodes +** Launch a process on two external nodes + +#+BEGIN_SRC haskell +module Flapping + (flapper + ,flapping) +where + + +import Control.Monad.IO.Class (liftIO) +import Transient.Base (TransIO) +import Transient.Move (local,onAll,runAt,lliftIO,Node,Cloud,addNodes,listen,createNode,runCloudIO) +import GHCJS.HPlay.View (div,id,span) +import Data.Monoid ((<>)) +import Control.Applicative ((<|>),empty) +import Control.Monad (mapM) + +main :: IO () +main = do + -- creating two nodes on localhost + node1 <- createNode "localhost" 20000 + node2 <- createNode "localhost" 20001 + runCloudIO $ do + -- create 3 threads + -- one listen node1 + -- the other listen node 2 + -- the last one is the current thread + listen node1 <|> listen node2 <|> return () + -- on node1 return "hello" + r1 <- runAt node1 (return "hello") + -- on node2 return "world" + r2 <- runAt node2 (return "world") + -- the local thread print "hello world!" + local $ liftIO $ putStrLn (r1 <> " " <> r2 <> "!") +#+END_SRC + +** Now with =n= nodes: + + +#+BEGIN_SRC haskell +import Control.Monad.IO.Class (liftIO) +import Transient.Base (TransIO) +import Transient.Move (local,onAll,runAt,lliftIO,Node,Cloud,addNodes,listen,createNode,runCloudIO) +import GHCJS.HPlay.View (div,id,span) +import Data.Monoid ((<>)) +import Control.Applicative ((<|>),empty) +import Control.Monad (mapM) +import Data.Foldable (traverse_) + +func = a -> m a +func n = return ("received: " <> show n) + +main :: IO () +main = do + let nbNodes = 10 + -- create nbNodes which can receive orders to execute functions + nodes <- traverse (createNode "localhost") [20000..(20000 + nbNodes - 1)] + runCloudIO $ do + -- make nbNodes threads listening to all created nodes + foldl (<|>) empty (map listen nodes) <|> return () + r <- traverse (\n -> runAt (nodes !! n) (func n)) + [0..(fromIntegral nbNodes - 1)] + -- local to go from TransIO -> Cloud + -- liftIO to go from IO -> TransIO + local $ liftIO $ traverse_ print r +#+END_SRC + +** More details + +#+BEGIN_SRC haskell +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +module Flapping + (flapping) +where + +-- We use protolude to make things safer by default +-- and use less imports at the same time +-- Yeah, Base.Prelude is pretty fucked up +-- Not good for beginner neither for advanced users +import Protolude hiding (async, local) + +import Transient.Base (async, keep') +import Transient.Move (Cloud, Node, addNodes, createNode, listen, + lliftIO, local, onAll, runAt, runCloudIO) +-- import GHCJS.HPlay.View (div,id,span) + +func :: Int -> Cloud Text +func n = return ("received: " <> show n) + +flapping :: IO () +flapping = do + let nbNodes = 100 + -- create nbNodes which can receive orders to execute functions + nodes <- traverse (createNode "localhost") [20000..(20000 + nbNodes - 1)] + runCloudIO $ do + -- make nbNodes threads listening to all created nodes + foldl (<|>) empty (map listen nodes) <|> return () + -- zip nodes ([1..] :: [Int]) => [(node1,1), (node2,2),...] + -- then we use these couples of type (Node,Int) to run some process + -- on another node + -- the & just reverse the order of function application + -- I prefer to say, take theses objects and do this thing to them + -- instead of + -- do this thing to all of theses objects + r <- zip nodes ([1..] :: [Int]) & + traverse (\(node,n) -> runAt node (func n)) + + -- local to go from TransIO -> Cloud + -- liftIO to go from IO -> TransIO + -- so + -- local . liftIO :: IO -> Cloud + -- is just here for the plumbing + local . liftIO $ traverse_ putText r +#+END_SRC + +Results are in order, because traverse is sequential diff --git a/img/Scale drives deep learning progress.png b/img/Scale drives deep learning progress.png new file mode 100644 index 00000000..6ba1a878 Binary files /dev/null and b/img/Scale drives deep learning progress.png differ diff --git a/org-mode-cheat-sheet.org b/org-mode-cheat-sheet.org new file mode 100644 index 00000000..4ce47115 --- /dev/null +++ b/org-mode-cheat-sheet.org @@ -0,0 +1,51 @@ +#+Title: org-mode cheat sheet +#+TODO: TODO IN-PROGRESS WAITING | DONE CANCELED + +M = Command + +* Style +** *bold* +** /italic/ +** _underlined_ +** =code= +** ~verbatim~ +** +stroked+ +* Change Nodes Level +** =M-RIGHT= : move one level deeper the current node +** =M-S-RIGHT= : move one level deeper the current subtree +* Move nodes +** =M-UP= : move the node upper +** =M-DOWN= : move the node one line lower +** =M-A-UP= : move the subtree before the previous same level subtree +** =M-A-DOWN= : move the subtree after the next same level subtree +* Create Nodes +** =C-RET= Insert new heading after subtree +** =SPC m -= Turn (head)line into item (cycle item type) +** =SPC m *= Turn item/line into headline +* Editing +** =SPC m n= narrow view to subtree +** =SPC m N= widen view +** =SPC m b= focus subtree buffer +** =SPC m i l= insert link +* work with todos +** type =t= or =S-RIGHT= / =S-LEFT= to cycle from todo, done, nothing +** =, T= show todo tree +** TODO [#B] Full Task Example :tag1:tag2: +DEADLINE: <2019-03-10> + +:PROPERTIES: [] +:Effort: 2h +:Cost: $200 +:END: + +* Tables + +#+PLOT: title:"example" ind:1 type:2d with:lines +#+PLOT: labels:("first new label" "second column" "last column") +#+TBLNAME:org-plot-example-1 +| var | x | y | +|-----+----+-----| +| 0.1 | -1 | 0 | +| 0.2 | 1 | 30 | +| 0.3 | 2 | 80 | +| 0.4 | 3 | 110 | diff --git a/reclamation-demenagement.org b/reclamation-demenagement.org new file mode 100644 index 00000000..364ef767 --- /dev/null +++ b/reclamation-demenagement.org @@ -0,0 +1,301 @@ +#+Title: Réclamation Déménagement + +* Entretien & Devis + +Madame, Monsieur, + +Nous avons confié la réalisation de notre déménagement à votre société. Avant +cela nous étions passé par un site internet qui nous permettait d'entrer en +contact et de réaliser des devis auprès de différentes sociétés de déménagement. + +Votre société CEDS nous a contacté par le biais de votre commerciale. Après +discussion il a été convenu d'un rendez-vous environ 3 semaines avant la date +prévue car nous n'étions pas sûr du volume dont nous avions besoin. + +Nous désirions qu'un professionnel constate le travail qu'il y avait à réaliser +car nous voulions que notre déménagement se passe du mieux possible sans +mauvaise surprise le jour J pour nous comme pour la société concernée. + +Lors de cet entretien nous avions spécifié très clairement que le déménagement +devait se dérouler le 22 décembre, ni avant (nous devions signer chez le notaire +le 21 décembre) ni après car ma femme avait des impératifs de travail. Nous +avions même précisé que si la date n'était pas disponible nous ne désirions pas +aller plus loin. + +Toujours lors de cet entretien et avec la commerciale nous avons vérifié à +l'aide de google map et google street que les rues n'étaient pas accessibles aux +véhicules de plus de 5,5T. Elle nous avait rassuré en nous parlant de deux +voyages ou d'un transbordement. + +Nous avions également demandé si la société employait des sous-traitants. Elle +nous avait répondu que cela arrivait mais qu'il (la société CEDS) ne travaillait +qu'avec des personnes de confiances qu'il connaissait bien. Puis elle avait +éludé la suite de la discussion en nous disant qu'il fallait aussi qu'on se +fasse mutuellement confiance. + +Après cet entretien, nous avons décidé de signer un contrat avec votre société +et puisque je suis à la fois très occupé et que j'ai connu des épisodes de +lombalgies aïgues (dont un ayant causé un arrêt de travail) nous avons souscris +un contrat catégorie 2 confort afin que je n'ai pas de manutention à effectuer, +où votre société s'engage à : + +- mettre des emballages à notre disposition ; +- emballer et déballer tous les objets fragiles ; +- mettre en penderies les vêtements sur cintres, précisons que nous avions + convenu avec la commerciale que 2 penderies étaient nécessaires) +- conditionner les matelas et sommiers sous housses et protéger le mobilier ; +- démonter et remonter le mobilier non fixé +- charger et transporter les bien en camion capitonné +- décharger et remettre en place le mobilier. + +De notre coté nous nous sommes engagé à emballer et déballer tous les objets non +fragiles. Ajoutons que le déménagement comprenait le transport d'un piano +(facturé 150€) ainsi qu'un échange de meuble entre Vitrolle et notre nouvel +appartement. Tout celà pour un montant de 2154€. + +* Appel téléphonique et surfacturation + +Huit à neuf jours avant la date fixée j'ai reçu un appel me disant qu'un +transbordement allait être nécessaire car la rue d'arrivée ne permettait pas +l'accès à un camion plus gros que 5,5T ; et tout cela pour 150€ de plus. +Augmentation que mon épouse a refusé de payer dans la mesure où votre société avait +connaissance de ces faits le jour où le devis a été établi. + +* Veille: 21 décembre 2016 + +Le 21 décembre 2016 à 20h45, nous avons reçu un appel des déménageurs nous +demandant de voir l'appartement afin de mieux s'organiser pour le lendemain. +Afin de faciliter le déménagement et leur travail nous avons accepté. Ils sont +arrivés aux environs de 21h30 et ont fait un rapide tour de l'appartement. En +partant ils nous ont précisé qu'ils commenceraient entre 8h et 8h15 le +lendemain. + +Nous ne les reverrons plus. + +* Date prévue de déménagement: 22 décembre 2016 + +Le jour J tout était prêt. Mon épouse est partie sur le lieu de notre future +résidence pour transporter les enfants et nos chats afin qu'ils ne dérangent +pas les déménageurs. Après 9h30 un camion (grosse contenance, 19T) et son +chauffeur non accompagné des deux déménageurs que nous avions vu la veille s'est +présenté. + +À la demande du chauffeur c'est moi qui l'ai aidé à gérer la circulation pour +qu'il puisse manœuvrer et entrer dans la résidence. Le chauffeur m'explique +qu'il n'arrive pas à joindre les deux autres personnes. Inquiêt j'essaye d'en +apprendre plus, il m'explique qu'il a dormi dans le camion et que ses deux +collègues sont partis pour aller dormir dans un hôtel la veille et qu'ils ne +répondent plus ce matin. + +Il m'explique que pour gagner du temps nous allons commencer à descendre les +matelas et les planches. Je dois l'aider à descendre des meubles dans l'assenceur +et à transporter les matelas (ce sont des futons difficiles à manipuler). + +Ces descentes partielles de meubles sont entrecoupées par les appels du +chauffeur à ses responsables qui lui disent qu'il doit commencer le déménagement +et que les deux déménageurs vont finir par arriver. + +Après 10h mon épouse a appelé le standard de CEDS expliquant la situation. Ils +nous répondent qu'ils se renseignent et qu'ils nous tiennent au courant. Plus +tard, vers 11h sans réponse de leur part, c'est moi qui appelle le standard. Je +donne mon nom et j'explique de nouveau la situation. Apparemment mon +interlocuteur est au courant. La personne au bout du fil m'explique qu'en effet +deux des déménageurs sont accidentés. Je m'inquiète un peu pour eux. Il poursuit +en m'expliquant qu'ils ont été accidenté sur un chantier la veille. Chose qui me +semble évidemment impossible puisque je les ai vu la veille à 21h30. Lorsque je +lui explique celà, il me répond que ce n'était pas eux. Evidemment mon sang n'a +fait qu'un tour et quand je hausse le ton, il se met sur la défensive et +finalement quand je reprends la parole que je lui explique que je les ai vu la +veille à 21h30. Il me dit, et je cite : "Je vous mens par omission". Il poursuit +en me disant qu'il va me rappeler rapidement. + +Je refuse que le déménagement continue sans la présence des deux autres intervenants. +Mes meubles sont à l'extérieur à moitié protégés. + +Sans retour je fini par rappeler à 12h05, je lui explique que s'il n'est pas +capable de trouver une autre solution je préfère tout annuler. Il me répond +alors qu'il me rappellera à 12h30 avec et ce sont ses mots "une réponse +définitive". + +Entre temps comme il est difficile de joindre la société j'appelle aussi la +commerciale elle aussi au courant de la situation. + +Pendant ce temps, le chauffeur m'explique que sa direction lui dit qu'il va +trouver deux personnes, qu'elles seront disponibles en début d'après midi et que +le chauffeur doit aller les chercher. + +Je m'aperçois vers 13h que le chauffeur à laissé le camion ouvert devant +l'entrée de mon immeuble. Mes meubles sont laissés sans surveilances à +l'extérieur. Je décide d'attendre jusqu'à 13h30. M'apercevant que la situation +va difficilement être gérable en calculant le temps nécéssaire pour finir le +déménagement, je décide donc de remonter tous les meubles et les matelas seul +dans l'appartement. + +Je ne reverrai plus le chauffeur. + +Vers 15h30, la commerciale nous appelle pour nous proposer une solution pour +déménager le lendemain que j'accepte faute de mieux. + +Avec mon épouse nous nous retrouvons donc dans une situation délicate où nous +n'avons plus la possibilité de dormir sur place. Nous devons donc déménager +nous-même notre literie. Ce que nous faisons avec nos véhicules personnels. + +Le camion est toujours dans la résidence après notre dernier départ ce jour là à +17h30. Nous expliquons la situation à la gardienne de notre résidence, seule +personne capable de réouvrir la chaîne pour libérer le camion. + +Nous faisons de notre mieux pour déménager et installer notre literie pour +dormir dans notre nouvel appartement. + +À 19h le chauffeur du camion nous téléphone. Nous le redirigeons vers la +gardienne qui n'était plus présente passé 19h. Il nous recontacte à 19h15 nous +demandant de venir lui ouvrir la chaîne et il nous explique que les déménageurs +attendus étaient au commissariat. + +Nous refusons de perdre 50 minutes pour lui ouvrir la chaîne et le portail +sachant que nous devions nous occuper de nourrir nos enfants et de les installer +dans un lieux décent pour la nuit. + +* Deuxième jour: 23 décembre 2016 + +** Premier voyage + +Le deuxième jour, les déménageurs viennent de Marseille et arrivent à Saint +Laurent vers 12h dans un véhicule de moins de 5,5T. Je suis seul avec eux car +mon épouse travaille, (elle est infirmière et travaille de 8h à 20h). + +Le déménagement commence à 12h c'est moi qui démonte ma table pour faire gagner +du temps. Un des déménageur s'occupe d'emballer le fragile en faisant celà il +utilise un cutter pour couper le papier bulle directement sur notre table de +ferme en chêne. Lorsque je m'en aperçois, je lui explique gentillement de mettre +un plaque en bois pour protéger. Ce qu'il fait pendant quelques minutes, puis +dès que j'ai le dos tourné n'utilise plus la plaque. + +Assez vite les déménageurs décident de réaliser deux voyages. Ils déscendent le +piano lors du premier voyage et l'entreprosent dans le camion. + +Je parle des vêtements sur cintres ils m'expliquent qu'ils n'ont qu'un seul +carton faisant penderie. Bien insuffisant car ils nous en fallait deux comme +précisé lors de l'évaluation des besoins. À charge pour nous de les transporter. + +Je me rends avec eux dans mon sous-sol pour leur montrer ce qui doit être +déménagé. + +Un des déménageurs m'explique que pour tout ce qui est fragile, il vaut mieux +que je le déménage moi même dans mon véhicule personnel. Je charge donc ma C4 +Picasso 7 places de beaucoup d'objets fragiles : + +- luminaire +- Les verres les plus onéreux de notre service +- et objets divers + +Ils se chargent de finir de vider la cave (selon leur dire) et nous partons pour +le premier voyage. Juste avant de partir, je leur demande s'ils sont au courant +de places de parking réservées devant notre appartement. Lorsque j'explique au +responsable que les places étaient réservées la veille mais qu'à ma connaissance +elles ne le seront pas aujourd'hui son attitude change du tout au tout. + +Il s'inquiète, il m'explique que s'il avait su, il aurait refusé le contrat. +J'apprend alors qu'il y a un contrat. Pendant un moment je me suis fortement +inquieté pensant qu'il ne réaliserait pas le second voyage. +Il me rassure cependant. + +Nous arrivons à notre nouvel appartement pour vider le camion. Les places sont +occupées et beaucoup de temps est perdu pour laisser passer les véhicules. + +Le déménageur m'explique qu'après mon déménagement ils vont en faire un autre à +Nice le soir même. + +J'aide les déménageurs en portant moi même ainsi que mon fils de 14 ans des +cartons et certains meubles. Ils commencent à mettre les meubles dans la pièce +principale, comme je suis seul, j'ai du mal à expliquer la répartition des +meubles (il était prévu que ce soit mon épouse qui s'en occupe). + +Certains meubles ont été montés à tort alors qu'ils devaient aller au garage. +D'autres ont été entreposés dans la mauvaise pièce. Lorsque j'explique tout celà +je sens très bien un agacement, malheureusement, je ne pouvais pas être partout. + +Ils devaient monter le piano, mais ils avaient oublier une planche à roulette. +Le piano fera donc un aller-retour. + +** Second voyage + +Pendant le retour mon fils reste dans le nouvel appartement, il essai +d'organiser les cartons déposés en vrac, afin de libérer de l'espace pour le +deuxième transport. + +Lors du second voyage, il fait nuit, j'aide toujours les déménageurs. + +Juste avant le second départ, dans le salon il reste un amas d'objets divers +fragiles que le déménageur me conseille de déménager plus tard dans ma C4. + +Ce que je ne peux pas faire le soir même car elle est déjà remplie par le +premier voyage et je n'ai pas eu le temps de la vider. Ils ne m'ont pas aidé à +vider mon véhicule. + +Cette fois-ci mon épouse est rentrée il est 20h40, elle découvre que beaucoup de +meubles sont mal rangés. Cette fois-ci j'ai la possibilité de rester en bas pour +aider les déménageurs à vider le camion et aussi à mieux gérer la répartition +entre les meubles qui doivent aller dans le garage et ceux qui doivent aller +dans l'appartement. + +Mon épouse demande au responsable de déplacer les meubles dans les bonnes +pièces. Ce qu'il fait avec l'aide de notre fils et de mon épouse qui a déjà +travaillé 12h. + +Par la suite, le déménageur s'inquiète du déménagement du piano. Les déménageurs +nous demandent de les aider à monter l'instrument à l'intérieur de +l'appartement. Ce que nous sommes bien obligé de faire. Mon fils est en haut des +marches rejoins par deux déménageurs, un troisième est sur le coté, et mon +épouse et moi nous poussons vers le haut. + +Les déménageurs partent sans remonter les meubles vers 22h30. + +* Suite du déménagement. + +À ce jour nous ne trouvons pas la visserie très particulière permettant de +remonter le bureau de ma fille. J'ai cherché ces vis à Brico Depot, à Castorama +en demandant à chaque fois l'avis des responables de rayon. Ils m'ont expliqué +que ces vis seraient certainement introuvables dans le commerce rendant notre +bureau inutilisable. + +En examinant notre table de ferme, nous voyons qu'il y a beaucoup de coups de +cutter visibles. + +Une marche de notre escalier en bois a été abîmée lors de la montée du piano. + +Lors de notre retour au premier appartement, j'ai eu la mauvaise surprise de +constater que beaucoup d'objets ont été "oubliés": +- une caisse de livre ; +- un fer à repassé dans un carton ; +- un ventilateur... + +Le tout nécessitant deux aller-retour en C4. + +Autant vous dire que nous ne sommes pas du tout satisfaits du niveau de la +prestation qui nous a été fournie et du manque du professionnalisme de vos +services. + +J'ai à ce jour une douleur lombaire que je vais avoir du mal à faire passer. + +Il est évident que le volume réel transporté était très en dessous du volume prévu. +Nous avons fait de 8 à 10 voyages de C4 de plus que prévu. + +Nous estimons que nous avons subit un grave préjudice. Un stress très important +pour notre famille. De l'anxiété et un retard qui s'est répercuté sur les +travaux que nous avions à faire sur l'appartement que nous quittons. + +Les prestations fournies n'ont pas été à la hauteur de ce que nous avons payé. + +Nous vous demandons donc un remboursement conséquent du montant que nous avons +dû payer. Sans remboursement satisfant d'ici 15 jours, nous transmettrons le +dossier à l'inspection du travail, la répression des fraudes, la société des +consommateurs ainsi qu'à notre assistance juridique. + +Bien entendu nous pouvons vous fournir des témoignages de notre voisinage, ainsi +que d'autres preuves de tout ce que nous avançons. + +Dans l'attente d'une réponse, + +le 28 décembre 2016, +Yann Esposito.