initial commit
This commit is contained in:
commit
4e1befea7b
17 changed files with 2059 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
ltximg
|
BIN
Archive.org.gpg
Normal file
BIN
Archive.org.gpg
Normal file
Binary file not shown.
BIN
Cisco.org.gpg
Normal file
BIN
Cisco.org.gpg
Normal file
Binary file not shown.
218
Deep-Learning.org
Normal file
218
Deep-Learning.org
Normal file
|
@ -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
|
Binary file not shown.
After Width: | Height: | Size: 392 KiB |
Binary file not shown.
After Width: | Height: | Size: 392 KiB |
296
Nicolas.org
Normal file
296
Nicolas.org
Normal file
|
@ -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 ????
|
65
TODO.org
Normal file
65
TODO.org
Normal file
|
@ -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.
|
213
blog-FP-Survey.org
Normal file
213
blog-FP-Survey.org
Normal file
|
@ -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
|
94
blog-false-programmer-problems.org
Normal file
94
blog-false-programmer-problems.org
Normal file
|
@ -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 <http://utf8everywhere.org>
|
||||||
|
|
||||||
|
** Readability:
|
||||||
|
- lenght of line (33em)
|
62
blog-on-SCRUM.org
Normal file
62
blog-on-SCRUM.org
Normal file
|
@ -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.
|
69
blog-programming-choices.org
Normal file
69
blog-programming-choices.org
Normal file
|
@ -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.
|
504
blog-raw-haskell-web-app.org
Normal file
504
blog-raw-haskell-web-app.org
Normal file
|
@ -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 <http://localhost:8080/>
|
||||||
|
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
|
185
blog-transient.org
Normal file
185
blog-transient.org
Normal file
|
@ -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
|
BIN
img/Scale drives deep learning progress.png
Normal file
BIN
img/Scale drives deep learning progress.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 392 KiB |
51
org-mode-cheat-sheet.org
Normal file
51
org-mode-cheat-sheet.org
Normal file
|
@ -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 |
|
301
reclamation-demenagement.org
Normal file
301
reclamation-demenagement.org
Normal file
|
@ -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.
|
Loading…
Reference in a new issue