initial commit

This commit is contained in:
Yann Esposito (Yogsototh) 2017-08-24 20:58:13 +02:00
commit 4e1befea7b
Signed by untrusted user who does not match committer: yogsototh
GPG key ID: 7B19A4C650D59646
17 changed files with 2059 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
ltximg

BIN
Archive.org.gpg Normal file

Binary file not shown.

BIN
Cisco.org.gpg Normal file

Binary file not shown.

218
Deep-Learning.org Normal file
View 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
View 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
View 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
View 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

View 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
View 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.

View 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.

View 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
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 392 KiB

51
org-mode-cheat-sheet.org Normal file
View 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 |

View 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.