@@ @@html:@@ 2019-07-28: @@html:@@ [[file:posts/autoload-emacs-script-by-project.org][Autoload Script by project]] @@html:@@ @@html:
@@
@@html:
@@ @@html:@@ 2019-07-07: @@html:@@ [[file:posts/2019-07-04-static-org-publish.org][Static blog with org-mode]] @@html:@@ @@html:
@@
#+end_archive
diff --git a/src/assets/css/minimalist.css b/src/assets/css/minimalist.css
index 09d8366..38db000 100644
--- a/src/assets/css/minimalist.css
+++ b/src/assets/css/minimalist.css
@@ -27,42 +27,14 @@ body {
-moz-hyphens:auto;
-ms-hyphens:auto;
}
-#preamble {
- border-bottom: solid 1px;
-}
-#preamble h1 {
- margin-bottom: 0;
-}
-#postamble {
- border-top: solid 1px;
-}
-#preamble,#postamble {
- padding: 10px 0;
-}
-.menu {
- opacity: 0.5;
-}
-.menu:hover, .menu:focus {
- opacity:1;
-}
-#content,.content {
- max-width: 50em;
- margin: 0 auto;
- padding: 10px;
-}
-#content *:first-child {
- margin-top: 0;
-}
-
h1, h2, h3, h4, h5, h6, pre, code, blockquote, ol, ul, ol ol, ul ul, ul ol, ol
ul, li, p, section, header, footer {
float: none;
margin: 0;
padding: 0;
}
-
h1, h2, h3, h4, h5, h6, pre, code, blockquote, p, ul, ol, section, header,
-.figure {
+figure {
margin-top: 20px;
margin-bottom: 20px;
}
@@ -152,7 +124,6 @@ blockquote:after {
position: absolute;
top: 0;
left: 0;
- opacity: 0.3;
}
li {
position: relative;
@@ -176,8 +147,6 @@ ol > li:before {
opacity: 0.5;
}
-/* colors */
-
img {
max-width: 100%;
max-height: 800px;
@@ -188,13 +157,6 @@ p > img, li > img {
margin: 0;
vertical-align: middle;
}
-footer {
- font-size: 0.8em;
-}
-.article-date {
- opacity: 0.5;
- font-size: 0.8;
-}
table {
width: 100%;
margin: 20px 0;
@@ -219,15 +181,32 @@ navigation {
navigation > a {
margin-right: 10px;
}
-.footpara { display: inline; }
-.footdef > sup {
- vertical-align: middle;
-}
-.footdef > sup::after {
- content: ": ";
-}
-/* org mode statuses */
+/* org mode ids and classes */
+.figure {
+ margin-top: 20px;
+ margin-bottom: 20px;
+}
+#preamble {
+ border-bottom: solid 1px;
+}
+#preamble h1, #preamble h2 {
+ margin: 0;
+}
+#postamble {
+ border-top: solid 1px;
+}
+#preamble,#postamble {
+ padding: 10px 0;
+}
+#content,.content {
+ max-width: 50em;
+ margin: 0 auto;
+ padding: 10px;
+}
+#content *:first-child {
+ margin-top: 0;
+}
.timestamp-wrapper {
font-size: 12px;
}
@@ -236,6 +215,21 @@ navigation > a {
font-weight: bold;
padding: 1px 1ex;
}
+.article-date {
+ font-size: 0.8;
+ font-style: italic;
+ float: right;
+}
+.footpara {
+ display: inline;
+}
+.footdef > sup {
+ vertical-align: middle;
+}
+.footdef > sup::after {
+ content: ": ";
+}
+
/* colors theme */
:root {
@@ -258,7 +252,8 @@ navigation > a {
--green: #859900;
--transparent: rgba(255,255,255,0);
- --main-background: #00151b; /* 0.5 darker than #002b36; */
+ /* --main-background: #00151b; /* 0.5 darker than #002b36; */
+ --main-background: var(--base03); /* 0.5 darker than #002b36; */
--main-foreground: var(--base1);
--second-foreground: var(--base0);
--soft-foreground: var(--base01);
@@ -279,7 +274,6 @@ navigation > a {
--todo-txt: #FFF;
}
}
-
body {
background: var(--main-background);
color: var(--main-foreground);
@@ -301,6 +295,12 @@ pre::after,pre::before,hr:after {
a:hover, a:active, a:focus {
color: var(--yellow);
}
+navigation a, navigation a:visited {
+ color: var(--soft-foreground);
+}
+navigation a:focus, navigation a:hover {
+ color: var(--yellow);
+}
thead {
background-color: var(--reveal-background);
color: var(--second-fg);
@@ -308,24 +308,20 @@ thead {
tr:hover {
background-color: var(--reveal-background);
}
-#postamble:hover, #preamble:hover {
- background-color: var(--reveal-background);
- border-color: var(--border-color);
-}
h1 {
- color: var(--violet);
-}
-h2 {
color: var(--magenta);
}
+h2 {
+ color: var(--violet);
+}
h3 {
- color: var(--red);
+ color: var(--blue);
}
h4 {
- color: var(--orange);
+ color: var(--cyan);
}
h5 {
- color: var(--yellow);
+ color: var(--green);
}
h6 {
color: var(--green);
@@ -336,9 +332,15 @@ table, td, th {
code {
background: var(--reveal-background);
}
+blockquote:after {
+ color: var(--soft-foreground);
+}
#preamble,#postamble {
border-color: var(--transparent);
}
+.article-date {
+ color: var(--soft-foreground);
+}
/* -------- */
/* org colors */
.todo, .done {
diff --git a/src/assets/favicon.ico b/src/assets/favicon.ico
new file mode 100644
index 0000000..3372902
Binary files /dev/null and b/src/assets/favicon.ico differ
diff --git a/src/demo.org b/src/demo.org
index 284a2a4..e5f28f5 100644
--- a/src/demo.org
+++ b/src/demo.org
@@ -36,6 +36,9 @@ There should be a forced newline.
It lets you and others work together on projects from anywhere.
*** Level 3
+ :PROPERTIES:
+ :CUSTOM_ID: level-3
+ :END:
#+begin_quote
This is a blockquote following a header.
@@ -45,6 +48,9 @@ There should be a forced newline.
#+end_quote
**** Level 4
+ :PROPERTIES:
+ :CUSTOM_ID: level-4
+ :END:
#+begin_src javascript
// Javascript code with syntax highlighting.
@@ -78,6 +84,9 @@ There should be a forced newline.
#+end_src
***** Level 5
+ :PROPERTIES:
+ :CUSTOM_ID: level-5
+ :END:
- this is an unordered list following a header.
- this is an unordered list following a header.
@@ -121,6 +130,9 @@ Bad too wide table...
------
*** Here is an unordered list:
+ :PROPERTIES:
+ :CUSTOM_ID: here-is-an-unordered-list-
+ :END:
- level 1 item
- level 2 item
@@ -140,27 +152,39 @@ Bad too wide table...
- level 2 item
**** Image test
+ :PROPERTIES:
+ :CUSTOM_ID: image-test
+ :END:
an image:
#+CAPTION: Testing include an image
#+NAME: fig:test-image
#+ATTR_HTML: The Experiment
-[[../assets/img/a.png]]
+[[../img/a.png]]
We could try inline image
-[[../assets/img/a.png]]
+[[../img/a.png]]
just to check.
-- [[../assets/img/a.png]] item with img
- - [[../assets/img/a.png]] item with img
- - [[../assets/img/a.png]] item with img
- - [[../assets/img/a.png]] item with img
+- [[../img/a.png]] item with img
+ - [[../img/a.png]] item with img
+ - [[../img/a.png]] item with img
+ - [[../img/a.png]] item with img
***** TODO todo
+ :PROPERTIES:
+ :CUSTOM_ID: todo
+ :END:
****** IN-PROGRESS in-progress
+ :PROPERTIES:
+ :CUSTOM_ID: in-progress
+ :END:
******* IN-REVIEW in-review
+ :PROPERTIES:
+ :CUSTOM_ID: in-review
+ :END:
****** HOLD on hold state
- State "HOLD" from "IN-REVIEW" [2019-07-09 Tue 13:44] \\
some reason
diff --git a/src/drafts/Haskell-the-Hard-Way.org b/src/drafts/Haskell-the-Hard-Way.org
new file mode 100644
index 0000000..72333ec
--- /dev/null
+++ b/src/drafts/Haskell-the-Hard-Way.org
@@ -0,0 +1,3772 @@
+#+TITLE: Learn Haskell Fast and Hard
+#+AUTHOR: Yann Esposito
+#+KEYWORDS: Haskell, programming, functional, tutorial
+#+OPTIONS: auto-id:t
+#+PROPERTY: eval no
+
+blogimage("magritte_pleasure_principle.jpg","Magritte pleasure
+principle")
+
+%tldr A very short and dense tutorial for learning Haskell.
+
+Thanks to:
+
+- [[https://plus.google.com/u/0/113751420744109290534][Oleg Taykalo]]
+ you can find a Russian translation here:
+ [[http://habrahabr.ru/post/152889/][Part 1]] /&/
+ [[http://habrahabr.ru/post/153383/][Part 2]],
+- [[http://silly-bytes.blogspot.fr][Daniel Campoverde]] for the Spanish
+ translation here:
+ [[http://silly-bytes.blogspot.fr/2016/06/aprende-haskell-rapido-y-dificil_29.html][Aprende
+ Haskell rápido y difícil]],
+- [[http://github.com/joom][Joomy Korkut]] for the Turkish translation
+ here: [[https://github.com/joom/zor-yoldan-haskell][Zor Yoldan
+ Haskell]].
+
+I really believe all developers should learn Haskell. I don't think
+everyone needs to be super Haskell ninjas, but they should at least
+discover what Haskell has to offer. Learning Haskell opens your mind.
+
+Mainstream languages share the same foundations:
+
+- variables
+- loops
+- pointers[fn:1]
+- data structures, objects and classes (for most)
+
+Haskell is very different. The language uses a lot of concepts I had
+never heard about before. Many of those concepts will help you become a
+better programmer.
+
+But learning Haskell can be hard. It was for me. In this article I try
+to provide what I lacked during my learning.
+
+This article will certainly be hard to follow. This is on purpose. There
+is no shortcut to learning Haskell. It is hard and challenging. But I
+believe this is a good thing. It is because it is hard that Haskell is
+interesting.
+
+The conventional method to learning Haskell is to read two books. First
+[[http://learnyouahaskell.com]["Learn You a Haskell"]] and just after
+[[http://www.realworldhaskell.org]["Real World Haskell"]]. I also
+believe this is the right way to go. But to learn what Haskell is all
+about, you'll have to read them in detail.
+
+In contrast, this article is a very brief and dense overview of all
+major aspects of Haskell. I also added some information I lacked while I
+learned Haskell.
+
+The article contains five parts:
+
+- Introduction: a short example to show Haskell can be friendly.
+- Basic Haskell: Haskell syntax, and some essential notions.
+- Hard Difficulty Part:
+
+ - Functional style; a progressive example, from imperative to
+ functional style
+ - Types; types and a standard binary tree example
+ - Infinite Structure; manipulate an infinite binary tree!
+
+- Hell Difficulty Part:
+
+ - Deal with IO; A very minimal example
+ - IO trick explained; the hidden detail I lacked to understand IO
+ - Monads; incredible how we can generalize
+
+- Appendix:
+
+ - More on infinite tree; a more math oriented discussion about
+ infinite trees
+
+#+BEGIN_QUOTE
+ Note: Each time you see a separator with a filename ending in =.lhs=
+ you can click the filename to get this file. If you save the file as
+ =filename.lhs=, you can run it with
+
+ #+BEGIN_SRC bash
+ runhaskell filename.lhs
+ #+END_SRC
+
+ Some might not work, but most will. You should see a link just below.
+#+END_QUOTE
+
+* Introduction
+ :PROPERTIES:
+ :CUSTOM_ID: introduction
+ :END:
+
+** Install
+ :PROPERTIES:
+ :CUSTOM_ID: install
+ :END:
+
+blogimage("Haskell-logo.png", "Haskell logo")
+
+There are different way to install Haskell, I would recommend to use
+[[https://haskellstack.org][=stack=]].
+
+There are other way to install Haskell on your system you could visit,
+you can learn more about it by visiting
+[[https://haskell.org][haskell.org]] or
+[[https://haskell-lang.org][haskell-lang.org]]
+
+Tools:
+
+- =ghc=: Compiler similar to gcc for =C=.
+- =ghci=: Interactive Haskell (REPL)
+- =runhaskell=: Execute a program without compiling it. Convenient but
+ very slow compared to compiled programs.
+
+** Don't be afraid
+ :PROPERTIES:
+ :CUSTOM_ID: don't-be-afraid
+ :END:
+
+blogimage("munch_TheScream.jpg","The Scream")
+
+Many books/articles about Haskell start by introducing some esoteric
+formula (quick sort, Fibonacci, etc...). I will do the exact opposite.
+At first I won't show you any Haskell super power. I will start with
+similarities between Haskell and other programming languages. Let's jump
+to the mandatory "Hello World".
+
+#+BEGIN_SRC haskell :eval never-export
+ main = putStrLn "Hello World!"
+#+END_SRC
+
+To run it, you can save this code in a =hello.hs= and:
+
+#+BEGIN_EXAMPLE
+ ~ runhaskell ./hello.hs
+ Hello World!
+#+END_EXAMPLE
+
+or if you use =stack= first run =stack setup= and then:
+
+#+BEGIN_EXAMPLE
+ ~ stack runhaskell ./hello.hs
+ Hello World!
+#+END_EXAMPLE
+
+You could also download the literate Haskell source. You should see a
+link just above the introduction title. Download this file as
+=00_hello_world.lhs= and:
+
+#+BEGIN_EXAMPLE
+ ~ runhaskell 00_hello_world.lhs
+ Hello World!
+#+END_EXAMPLE
+
+01_basic/10_Introduction/00_hello_world.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+01_basic/10_Introduction/10_hello_you.lhs
+
+Now, a program asking your name and replying "Hello" using the name you
+entered:
+
+#+BEGIN_SRC haskell :eval never-export
+ main = do
+ print "What is your name?"
+ name <- getLine
+ print ("Hello " ++ name ++ "!")
+#+END_SRC
+
+First, let us compare this with similar programs in a few imperative
+languages:
+
+#+BEGIN_SRC python
+ # Python
+ print "What is your name?"
+ name = raw_input()
+ print "Hello %s!" % name
+#+END_SRC
+
+#+BEGIN_SRC ruby
+ # Ruby
+ puts "What is your name?"
+ name = gets.chomp
+ puts "Hello #{name}!"
+#+END_SRC
+
+#+BEGIN_SRC C
+ // In C
+ #include
+ int main (int argc, char **argv) {
+ char name[666]; // <- An Evil Number!
+ // What if my name is more than 665 character long?
+ printf("What is your name?\n");
+ scanf("%s", name);
+ printf("Hello %s!\n", name);
+ return 0;
+ }
+#+END_SRC
+
+The structure is the same, but there are some syntax differences. The
+main part of this tutorial will be dedicated to explaining why.
+
+In Haskell there is a =main= function and every object has a type. The
+type of =main= is =IO ()=. This means =main= will cause side effects.
+
+Just remember that Haskell can look a lot like mainstream imperative
+languages.
+
+01_basic/10_Introduction/10_hello_you.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+01_basic/10_Introduction/20_very_basic.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+blogimage("picasso_owl.jpg","Picasso minimal owl")
+
+Before continuing you need to be warned about some essential properties
+of Haskell.
+
+/Functional/
+
+Haskell is a functional language. If you have an imperative language
+background, you'll have to learn a lot of new things. Hopefully many of
+these new concepts will help you to program even in imperative
+languages.
+
+/Smart Static Typing/
+
+Instead of being in your way like in =C=, =C++= or =Java=, the type
+system is here to help you.
+
+/Purity/
+
+Generally your functions won't modify anything in the outside world.
+This means they can't modify the value of a variable, can't get user
+input, can't write on the screen, can't launch a missile. On the other
+hand, parallelism will be very easy to achieve. Haskell makes it clear
+where effects occur and where your code is pure. Also, it will be far
+easier to reason about your program. Most bugs will be prevented in the
+pure parts of your program.
+
+Furthermore, pure functions follow a fundamental law in Haskell:
+
+#+BEGIN_QUOTE
+ Applying a function with the same parameters always returns the same
+ value.
+#+END_QUOTE
+
+/Laziness/
+
+Laziness by default is a very uncommon language design. By default,
+Haskell evaluates something only when it is needed. In consequence, it
+provides a very elegant way to manipulate infinite structures, for
+example.
+
+A last warning about how you should read Haskell code. For me, it is
+like reading scientific papers. Some parts are very clear, but when you
+see a formula, just focus and read slower. Also, while learning Haskell,
+it /really/ doesn't matter much if you don't understand syntax details.
+If you meet a =>>==, =<$>=, =<-= or any other weird symbol, just ignore
+them and follows the flow of the code.
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+You might be used to declaring functions like this:
+
+In =C=:
+
+#+BEGIN_SRC C
+ int f(int x, int y) {
+ return x*x + y*y;
+ }
+#+END_SRC
+
+In JavaScript:
+
+#+BEGIN_EXAMPLE
+ function f(x,y) {
+ return x*x + y*y;
+ }
+#+END_EXAMPLE
+
+in Python:
+
+#+BEGIN_SRC python
+ def f(x,y):
+ return x*x + y*y
+#+END_SRC
+
+in Ruby:
+
+#+BEGIN_SRC ruby
+ def f(x,y)
+ x*x + y*y
+ end
+#+END_SRC
+
+In Scheme:
+
+#+BEGIN_SRC scheme
+ (define (f x y)
+ (+ (* x x) (* y y)))
+#+END_SRC
+
+Finally, the Haskell way is:
+
+#+BEGIN_SRC haskell :eval never-export
+ f x y = x*x + y*y
+#+END_SRC
+
+Very clean. No parenthesis, no =def=.
+
+Don't forget, Haskell uses functions and types a lot. It is thus very
+easy to define them. The syntax was particularly well thought out for
+these objects.
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+A Type Example
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Although it is not mandatory, type information for functions is usually
+made explicit. It's not mandatory because the compiler is smart enough
+to discover it for you. It's a good idea because it indicates intent and
+understanding.
+
+Let's play a little. We declare the type using =::=
+
+#+BEGIN_SRC haskell :eval never-export
+ f :: Int -> Int -> Int
+ f x y = x*x + y*y
+
+ main = print (f 2 3)
+#+END_SRC
+
+#+BEGIN_EXAMPLE
+ ~ runhaskell 20_very_basic.lhs
+ 13
+#+END_EXAMPLE
+
+01_basic/10_Introduction/20_very_basic.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+01_basic/10_Introduction/21_very_basic.lhs
+
+Now try
+
+#+BEGIN_SRC haskell :eval never-export
+ f :: Int -> Int -> Int
+ f x y = x*x + y*y
+
+ main = print (f 2.3 4.2)
+#+END_SRC
+
+You should get this error:
+
+#+BEGIN_EXAMPLE
+ 21_very_basic.lhs:6:23:
+ No instance for (Fractional Int)
+ arising from the literal `4.2'
+ Possible fix: add an instance declaration for (Fractional Int)
+ In the second argument of `f', namely `4.2'
+ In the first argument of `print', namely `(f 2.3 4.2)'
+ In the expression: print (f 2.3 4.2)
+#+END_EXAMPLE
+
+The problem: =4.2= isn't an Int.
+
+01_basic/10_Introduction/21_very_basic.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+01_basic/10_Introduction/22_very_basic.lhs
+
+The solution: don't declare a type for =f= for the moment and let
+Haskell infer the most general type for us:
+
+#+BEGIN_SRC haskell :eval never-export
+ f x y = x*x + y*y
+
+ main = print (f 2.3 4.2)
+#+END_SRC
+
+It works! Luckily, we don't have to declare a new function for every
+single type. For example, in =C=, you'll have to declare a function for
+=int=, for =float=, for =long=, for =double=, etc...
+
+But, what type should we declare? To discover the type Haskell has found
+for us, just launch ghci:
+
+#+BEGIN_HTML
+
+ % ghci
+ GHCi, version 7.0.4: http://www.haskell.org/ghc/ :? for help
+ Loading package ghc-prim ... linking ... done.
+ Loading package integer-gmp ... linking ... done.
+ Loading package base ... linking ... done.
+ Loading package ffi-1.0 ... linking ... done.
+ Prelude> let f x y = x*x + y*y
+ Prelude> :type f
+ f :: Num a => a -> a -> a
+
+#+END_HTML
+
+Uh? What is this strange type?
+
+#+BEGIN_EXAMPLE
+ Num a => a -> a -> a
+#+END_EXAMPLE
+
+First, let's focus on the right part =a -> a -> a=. To understand it,
+just look at a list of progressive examples:
+
+| The written type | Its meaning |
+|--------------------+---------------------------------------------------------------------------|
+| =Int= | the type =Int= |
+| =Int -> Int= | the type function from =Int= to =Int= |
+| =Float -> Int= | the type function from =Float= to =Int= |
+| =a -> Int= | the type function from any type to =Int= |
+| =a -> a= | the type function from any type =a= to the same type =a= |
+| =a -> a -> a= | the type function of two arguments of any type =a= to the same type =a= |
+
+In the type =a -> a -> a=, the letter =a= is a /type variable/. It means
+=f= is a function with two arguments and both arguments and the result
+have the same type. The type variable =a= could take many different type
+values. For example =Int=, =Integer=, =Float=...
+
+So instead of having a forced type like in =C= and having to declare a
+function for =int=, =long=, =float=, =double=, etc., we declare only one
+function like in a dynamically typed language.
+
+This is sometimes called parametric polymorphism. It's also called
+having your cake and eating it too.
+
+Generally =a= can be any type, for example a =String= or an =Int=, but
+also more complex types, like =Trees=, other functions, etc. But here
+our type is prefixed with =Num a =>=.
+
+=Num= is a /type class/. A type class can be understood as a set of
+types. =Num= contains only types which behave like numbers. More
+precisely, =Num= is class containing types which implement a specific
+list of functions, and in particular =(+)= and =(*)=.
+
+Type classes are a very powerful language construct. We can do some
+incredibly powerful stuff with this. More on this later.
+
+Finally, =Num a => a -> a -> a= means:
+
+Let =a= be a type belonging to the =Num= type class. This is a function
+from type =a= to (=a -> a=).
+
+Yes, strange. In fact, in Haskell no function really has two arguments.
+Instead all functions have only one argument. But we will note that
+taking two arguments is equivalent to taking one argument and returning
+a function taking the second argument as a parameter.
+
+More precisely =f 3 4= is equivalent to =(f 3) 4=. Note =f 3= is a
+function:
+
+#+BEGIN_EXAMPLE
+ f :: Num a => a -> a -> a
+
+ g :: Num a => a -> a
+ g = f 3
+
+ g y ⇔ 3*3 + y*y
+#+END_EXAMPLE
+
+Another notation exists for functions. The lambda notation allows us to
+create functions without assigning them a name. We call them anonymous
+functions. We could also have written:
+
+#+BEGIN_EXAMPLE
+ g = \y -> 3*3 + y*y
+#+END_EXAMPLE
+
+The =\= is used because it looks like =λ= and is ASCII.
+
+If you are not used to functional programming your brain should be
+starting to heat up. It is time to make a real application.
+
+01_basic/10_Introduction/22_very_basic.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+01_basic/10_Introduction/23_very_basic.lhs
+
+But just before that, we should verify the type system works as
+expected:
+
+#+BEGIN_SRC haskell :eval never-export
+ f :: Num a => a -> a -> a
+ f x y = x*x + y*y
+
+ main = print (f 3 2.4)
+#+END_SRC
+
+It works, because, =3= is a valid representation both for Fractional
+numbers like Float and for Integer. As =2.4= is a Fractional number, =3=
+is then interpreted as being also a Fractional number.
+
+01_basic/10_Introduction/23_very_basic.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+01_basic/10_Introduction/24_very_basic.lhs
+
+If we force our function to work with different types, it will fail:
+
+#+BEGIN_SRC haskell :eval never-export
+ f :: Num a => a -> a -> a
+ f x y = x*x + y*y
+
+ x :: Int
+ x = 3
+ y :: Float
+ y = 2.4
+ -- won't work because type x ≠ type y
+ main = print (f x y)
+#+END_SRC
+
+The compiler complains. The two parameters must have the same type.
+
+If you believe that this is a bad idea, and that the compiler should
+make the transformation from one type to another for you, you should
+really watch this great (and funny) video:
+[[https://www.destroyallsoftware.com/talks/wat][WAT]]
+
+01_basic/10_Introduction/24_very_basic.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+blogimage("kandinsky_gugg.jpg","Kandinsky Gugg")
+
+I suggest that you skim this part. Think of it as a reference. Haskell
+has a lot of features. A lot of information is missing here. Come back
+here if the notation feels strange.
+
+I use the =⇔= symbol to state that two expression are equivalent. It is
+a meta notation, =⇔= does not exists in Haskell. I will also use =⇒= to
+show what the return value of an expression is.
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+#+BEGIN_EXAMPLE
+ True || False ⇒ True
+ True && False ⇒ False
+ True == False ⇒ False
+ True /= False ⇒ True (/=) is the operator for different
+#+END_EXAMPLE
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Powers
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+#+BEGIN_EXAMPLE
+ x^n for n an integral (understand Int or Integer)
+ x**y for y any kind of number (Float for example)
+#+END_EXAMPLE
+
+=Integer= has no limit except the capacity of your machine:
+
+#+BEGIN_EXAMPLE
+ 4^103
+ 102844034832575377634685573909834406561420991602098741459288064
+#+END_EXAMPLE
+
+Yeah! And also rational numbers FTW! But you need to import the module
+=Data.Ratio=:
+
+#+BEGIN_EXAMPLE
+ $ ghci
+ ....
+ Prelude> :m Data.Ratio
+ Data.Ratio> (11 % 15) * (5 % 3)
+ 11 % 9
+#+END_EXAMPLE
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Lists
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+#+BEGIN_EXAMPLE
+ [] ⇔ empty list
+ [1,2,3] ⇔ List of integral
+ ["foo","bar","baz"] ⇔ List of String
+ 1:[2,3] ⇔ [1,2,3], (:) prepend one element
+ 1:2:[] ⇔ [1,2]
+ [1,2] ++ [3,4] ⇔ [1,2,3,4], (++) concatenate
+ [1,2,3] ++ ["foo"] ⇔ ERROR String ≠ Integral
+ [1..4] ⇔ [1,2,3,4]
+ [1,3..10] ⇔ [1,3,5,7,9]
+ [2,3,5,7,11..100] ⇔ ERROR! I am not so smart!
+ [10,9..1] ⇔ [10,9,8,7,6,5,4,3,2,1]
+#+END_EXAMPLE
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Strings
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+In Haskell strings are list of =Char=.
+
+#+BEGIN_EXAMPLE
+ 'a' :: Char
+ "a" :: [Char]
+ "" ⇔ []
+ "ab" ⇔ ['a','b'] ⇔ 'a':"b" ⇔ 'a':['b'] ⇔ 'a':'b':[]
+ "abc" ⇔ "ab"++"c"
+#+END_EXAMPLE
+
+#+BEGIN_QUOTE
+ /Remark/: In real code you shouldn't use list of char to represent
+ text. You should mostly use =Data.Text= instead. If you want to
+ represent a stream of ASCII char, you should use =Data.ByteString=.
+#+END_QUOTE
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Tuples
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+The type of couple is =(a,b)=. Elements in a tuple can have different
+types.
+
+#+BEGIN_EXAMPLE
+ -- All these tuples are valid
+ (2,"foo")
+ (3,'a',[2,3])
+ ((2,"a"),"c",3)
+
+ fst (x,y) ⇒ x
+ snd (x,y) ⇒ y
+
+ fst (x,y,z) ⇒ ERROR: fst :: (a,b) -> a
+ snd (x,y,z) ⇒ ERROR: snd :: (a,b) -> b
+#+END_EXAMPLE
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Deal with parentheses
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+To remove some parentheses you can use two functions: =($)= and =(.)=.
+
+#+BEGIN_EXAMPLE
+ -- By default:
+ f g h x ⇔ (((f g) h) x)
+
+ -- the $ replace parenthesis from the $
+ -- to the end of the expression
+ f g $ h x ⇔ f g (h x) ⇔ (f g) (h x)
+ f $ g h x ⇔ f (g h x) ⇔ f ((g h) x)
+ f $ g $ h x ⇔ f (g (h x))
+
+ -- (.) the composition function
+ (f . g) x ⇔ f (g x)
+ (f . g . h) x ⇔ f (g (h x))
+#+END_EXAMPLE
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+01_basic/20_Essential_Haskell/10a_Functions.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Useful notations for functions
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Just a reminder:
+
+#+BEGIN_EXAMPLE
+ x :: Int ⇔ x is of type Int
+ x :: a ⇔ x can be of any type
+ x :: Num a => a ⇔ x can be any type a
+ such that a belongs to Num type class
+ f :: a -> b ⇔ f is a function from a to b
+ f :: a -> b -> c ⇔ f is a function from a to (b→c)
+ f :: (a -> b) -> c ⇔ f is a function from (a→b) to c
+#+END_EXAMPLE
+
+Remember that defining the type of a function before its declaration
+isn't mandatory. Haskell infers the most general type for you. But it is
+considered a good practice to do so.
+
+/Infix notation/
+
+#+BEGIN_SRC haskell :eval never-export
+ square :: Num a => a -> a
+ square x = x^2
+#+END_SRC
+
+Note =^= uses infix notation. For each infix operator there its
+associated prefix notation. You just have to put it inside parenthesis.
+
+#+BEGIN_SRC haskell :eval never-export
+ square' x = (^) x 2
+
+ square'' x = (^2) x
+#+END_SRC
+
+We can remove =x= in the left and right side! It's called η-reduction.
+
+#+BEGIN_SRC haskell :eval never-export
+ square''' = (^2)
+#+END_SRC
+
+Note we can declare functions with ='= in their name. Here:
+
+#+BEGIN_QUOTE
+ =square= ⇔ =square'= ⇔ =square''= ⇔ =square'''=
+#+END_QUOTE
+
+/Tests/
+
+An implementation of the absolute function.
+
+#+BEGIN_SRC haskell :eval never-export
+ absolute :: (Ord a, Num a) => a -> a
+ absolute x = if x >= 0 then x else -x
+#+END_SRC
+
+Note: the =if .. then .. else= Haskell notation is more like the =¤?¤:¤=
+C operator. You cannot forget the =else=.
+
+Another equivalent version:
+
+#+BEGIN_SRC haskell :eval never-export
+ absolute' x
+ | x >= 0 = x
+ | otherwise = -x
+#+END_SRC
+
+#+BEGIN_QUOTE
+ Notation warning: indentation is /important/ in Haskell. Like in
+ Python, bad indentation can break your code!
+#+END_QUOTE
+
+#+BEGIN_SRC haskell :eval never-export
+ main = do
+ print $ square 10
+ print $ square' 10
+ print $ square'' 10
+ print $ square''' 10
+ print $ absolute 10
+ print $ absolute (-10)
+ print $ absolute' 10
+ print $ absolute' (-10)
+#+END_SRC
+
+01_basic/20_Essential_Haskell/10a_Functions.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Hard Part
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+The hard part can now begin.
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Functional style
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+blogimage("hr_giger_biomechanicallandscape_500.jpg","Biomechanical
+Landscape by H.R. Giger")
+
+In this section, I will give a short example of the impressive
+refactoring ability provided by Haskell. We will select a problem and
+solve it in a standard imperative way. Then I will make the code evolve.
+The end result will be both more elegant and easier to adapt.
+
+Let's solve the following problem:
+
+#+BEGIN_QUOTE
+ Given a list of integers, return the sum of the even numbers in the
+ list.
+
+ example: =[1,2,3,4,5] ⇒ 2 + 4 ⇒ 6=
+#+END_QUOTE
+
+To show differences between functional and imperative approaches, I'll
+start by providing an imperative solution (in JavaScript):
+
+#+BEGIN_EXAMPLE
+ function evenSum(list) {
+ var result = 0;
+ for (var i=0; i< list.length ; i++) {
+ if (list[i] % 2 ==0) {
+ result += list[i];
+ }
+ }
+ return result;
+ }
+#+END_EXAMPLE
+
+In Haskell, by contrast, we don't have variables or a for loop. One
+solution to achieve the same result without loops is to use recursion.
+
+#+BEGIN_QUOTE
+ /Remark/: Recursion is generally perceived as slow in imperative
+ languages. But this is generally not the case in functional
+ programming. Most of the time Haskell will handle recursive functions
+ efficiently.
+#+END_QUOTE
+
+Here is a =C= version of the recursive function. Note that for
+simplicity I assume the int list ends with the first =0= value.
+
+#+BEGIN_SRC C
+ int evenSum(int *list) {
+ return accumSum(0,list);
+ }
+
+ int accumSum(int n, int *list) {
+ int x;
+ int *xs;
+ if (*list == 0) { // if the list is empty
+ return n;
+ } else {
+ x = list[0]; // let x be the first element of the list
+ xs = list+1; // let xs be the list without x
+ if ( 0 == (x%2) ) { // if x is even
+ return accumSum(n+x, xs);
+ } else {
+ return accumSum(n, xs);
+ }
+ }
+ }
+#+END_SRC
+
+Keep this code in mind. We will translate it into Haskell. First,
+however, I need to introduce three simple but useful functions we will
+use:
+
+#+BEGIN_SRC haskell :eval never-export
+ even :: Integral a => a -> Bool
+ head :: [a] -> a
+ tail :: [a] -> [a]
+#+END_SRC
+
+=even= verifies if a number is even.
+
+#+BEGIN_SRC haskell :eval never-export
+ even :: Integral a => a -> Bool
+ even 3 ⇒ False
+ even 2 ⇒ True
+#+END_SRC
+
+=head= returns the first element of a list:
+
+#+BEGIN_SRC haskell :eval never-export
+ head :: [a] -> a
+ head [1,2,3] ⇒ 1
+ head [] ⇒ ERROR
+#+END_SRC
+
+=tail= returns all elements of a list, except the first:
+
+#+BEGIN_SRC haskell :eval never-export
+ tail :: [a] -> [a]
+ tail [1,2,3] ⇒ [2,3]
+ tail [3] ⇒ []
+ tail [] ⇒ ERROR
+#+END_SRC
+
+Note that for any non empty list =l=, =l ⇔ (head l):(tail l)=
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/11_Functions.lhs
+
+The first Haskell solution. The function =evenSum= returns the sum of
+all even numbers in a list:
+
+#+BEGIN_SRC haskell :eval never-export
+ -- Version 1
+ evenSum :: [Integer] -> Integer
+
+ evenSum l = accumSum 0 l
+
+ accumSum n l = if l == []
+ then n
+ else let x = head l
+ xs = tail l
+ in if even x
+ then accumSum (n+x) xs
+ else accumSum n xs
+#+END_SRC
+
+To test a function you can use =ghci=:
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Here is an example of execution[fn:2]:
+
+#+BEGIN_HTML
+
+ *Main> evenSum [1..5]
+ accumSum 0 [1,2,3,4,5]
+ 1 is odd
+ accumSum 0 [2,3,4,5]
+ 2 is even
+ accumSum (0+2) [3,4,5]
+ 3 is odd
+ accumSum (0+2) [4,5]
+ 2 is even
+ accumSum (0+2+4) [5]
+ 5 is odd
+ accumSum (0+2+4) []
+ l == []
+ 0+2+4
+ 0+6
+ 6
+
+#+END_HTML
+
+Coming from an imperative language all should seem right. In fact, many
+things can be improved here. First, we can generalize the type.
+
+#+BEGIN_SRC haskell :eval never-export
+ evenSum :: Integral a => [a] -> a
+#+END_SRC
+
+#+BEGIN_SRC haskell :eval never-export
+ main = do print $ evenSum [1..10]
+#+END_SRC
+
+02_Hard_Part/11_Functions.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/12_Functions.lhs
+
+Next, we can use sub functions using =where= or =let=. This way our
+=accumSum= function won't pollute the namespace of our module.
+
+#+BEGIN_SRC haskell :eval never-export
+ -- Version 2
+ evenSum :: Integral a => [a] -> a
+
+ evenSum l = accumSum 0 l
+ where accumSum n l =
+ if l == []
+ then n
+ else let x = head l
+ xs = tail l
+ in if even x
+ then accumSum (n+x) xs
+ else accumSum n xs
+#+END_SRC
+
+#+BEGIN_SRC haskell :eval never-export
+ main = print $ evenSum [1..10]
+#+END_SRC
+
+02_Hard_Part/12_Functions.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/13_Functions.lhs
+
+Next, we can use pattern matching.
+
+#+BEGIN_SRC haskell :eval never-export
+ -- Version 3
+ evenSum l = accumSum 0 l
+ where
+ accumSum n [] = n
+ accumSum n (x:xs) =
+ if even x
+ then accumSum (n+x) xs
+ else accumSum n xs
+#+END_SRC
+
+What is pattern matching? Use values instead of general parameter
+names[fn:3].
+
+Instead of saying: =foo l = if l == [] then else = You simply
+state:
+
+#+BEGIN_SRC haskell :eval never-export
+ foo [] =
+ foo l =
+#+END_SRC
+
+But pattern matching goes even further. It is also able to inspect the
+inner data of a complex value. We can replace
+
+#+BEGIN_SRC haskell :eval never-export
+ foo l = let x = head l
+ xs = tail l
+ in if even x
+ then foo (n+x) xs
+ else foo n xs
+#+END_SRC
+
+with
+
+#+BEGIN_SRC haskell :eval never-export
+ foo (x:xs) = if even x
+ then foo (n+x) xs
+ else foo n xs
+#+END_SRC
+
+This is a very useful feature. It makes our code both terser and easier
+to read.
+
+#+BEGIN_SRC haskell :eval never-export
+ main = print $ evenSum [1..10]
+#+END_SRC
+
+02_Hard_Part/13_Functions.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/14_Functions.lhs
+
+In Haskell you can simplify function definitions by η-reducing them. For
+example, instead of writing:
+
+#+BEGIN_SRC haskell :eval never-export
+ f x = (some expresion) x
+#+END_SRC
+
+you can simply write
+
+#+BEGIN_SRC haskell :eval never-export
+ f = some expression
+#+END_SRC
+
+We use this method to remove the =l=:
+
+#+BEGIN_SRC haskell :eval never-export
+ -- Version 4
+ evenSum :: Integral a => [a] -> a
+
+ evenSum = accumSum 0
+ where
+ accumSum n [] = n
+ accumSum n (x:xs) =
+ if even x
+ then accumSum (n+x) xs
+ else accumSum n xs
+#+END_SRC
+
+#+BEGIN_SRC haskell :eval never-export
+ main = print $ evenSum [1..10]
+#+END_SRC
+
+02_Hard_Part/14_Functions.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/15_Functions.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Higher Order Functions
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+blogimage("escher_polygon.png","Escher")
+
+To make things even better we should use higher order functions. What
+are these beasts? Higher order functions are functions taking functions
+as parameters.
+
+Here are some examples:
+
+#+BEGIN_SRC haskell :eval never-export
+ filter :: (a -> Bool) -> [a] -> [a]
+ map :: (a -> b) -> [a] -> [b]
+ foldl :: (a -> b -> a) -> a -> [b] -> a
+#+END_SRC
+
+Let's proceed by small steps.
+
+#+BEGIN_SRC haskell :eval never-export
+ -- Version 5
+ evenSum l = mysum 0 (filter even l)
+ where
+ mysum n [] = n
+ mysum n (x:xs) = mysum (n+x) xs
+#+END_SRC
+
+where
+
+#+BEGIN_SRC haskell :eval never-export
+ filter even [1..10] ⇔ [2,4,6,8,10]
+#+END_SRC
+
+The function =filter= takes a function of type (=a -> Bool=) and a list
+of type =[a]=. It returns a list containing only elements for which the
+function returned =true=.
+
+Our next step is to use another technique to accomplish the same thing
+as a loop. We will use the =foldl= function to accumulate a value as we
+pass through the list. The function =foldl= captures a general coding
+pattern:
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Which can be replaced by:
+
+#+BEGIN_HTML
+
+ myfunc list = foldl barinitialValuelist
+
+#+END_HTML
+
+If you really want to know how the magic works, here is the definition
+of =foldl=:
+
+#+BEGIN_SRC haskell :eval never-export
+ foldl f z [] = z
+ foldl f z (x:xs) = foldl f (f z x) xs
+#+END_SRC
+
+#+BEGIN_SRC haskell :eval never-export
+ foldl f z [x1,...xn]
+ ⇔ f (... (f (f z x1) x2) ...) xn
+#+END_SRC
+
+But as Haskell is lazy, it doesn't evaluate =(f z x)= and simply pushes
+it onto the stack. This is why we generally use =foldl'= instead of
+=foldl=; =foldl'= is a /strict/ version of =foldl=. If you don't
+understand what lazy and strict means, don't worry, just follow the code
+as if =foldl= and =foldl'= were identical.
+
+Now our new version of =evenSum= becomes:
+
+#+BEGIN_SRC haskell :eval never-export
+ -- Version 6
+ -- foldl' isn't accessible by default
+ -- we need to import it from the module Data.List
+ import Data.List
+ evenSum l = foldl' mysum 0 (filter even l)
+ where mysum acc value = acc + value
+#+END_SRC
+
+We can also simplify this by using directly a lambda notation. This way
+we don't have to create the temporary name =mysum=.
+
+#+BEGIN_SRC haskell :eval never-export
+ -- Version 7
+ -- Generally it is considered a good practice
+ -- to import only the necessary function(s)
+ import Data.List (foldl')
+ evenSum l = foldl' (\x y -> x+y) 0 (filter even l)
+#+END_SRC
+
+And of course, we note that
+
+#+BEGIN_SRC haskell :eval never-export
+ (\x y -> x+y) ⇔ (+)
+#+END_SRC
+
+#+BEGIN_SRC haskell :eval never-export
+ main = print $ evenSum [1..10]
+#+END_SRC
+
+02_Hard_Part/15_Functions.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/16_Functions.lhs
+
+Finally
+
+#+BEGIN_SRC haskell :eval never-export
+ -- Version 8
+ import Data.List (foldl')
+ evenSum :: Integral a => [a] -> a
+ evenSum l = foldl' (+) 0 (filter even l)
+#+END_SRC
+
+=foldl'= isn't the easiest function to grasp. If you are not used to it,
+you should study it a bit.
+
+To help you understand what's going on here, let's look at a step by
+step evaluation:
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Another useful higher order function is =(.)=. The =(.)= function
+corresponds to mathematical composition.
+
+#+BEGIN_SRC haskell :eval never-export
+ (f . g . h) x ⇔ f ( g (h x))
+#+END_SRC
+
+We can take advantage of this operator to η-reduce our function:
+
+#+BEGIN_SRC haskell :eval never-export
+ -- Version 9
+ import Data.List (foldl')
+ evenSum :: Integral a => [a] -> a
+ evenSum = (foldl' (+) 0) . (filter even)
+#+END_SRC
+
+Also, we could rename some parts to make it clearer:
+
+#+BEGIN_SRC haskell :eval never-export
+ -- Version 10
+ import Data.List (foldl')
+ sum' :: (Num a) => [a] -> a
+ sum' = foldl' (+) 0
+ evenSum :: Integral a => [a] -> a
+ evenSum = sum' . (filter even)
+#+END_SRC
+
+It is time to discuss the direction our code has moved as we introduced
+more functional idioms. What did we gain by using higher order
+functions?
+
+At first, you might think the main difference is terseness. But in fact,
+it has more to do with better thinking. Suppose we want to modify our
+function slightly, for example, to get the sum of all even squares of
+elements of the list.
+
+#+BEGIN_EXAMPLE
+ [1,2,3,4] ▷ [1,4,9,16] ▷ [4,16] ▷ 20
+#+END_EXAMPLE
+
+Updating version 10 is extremely easy:
+
+#+BEGIN_SRC haskell :eval never-export
+ squareEvenSum = sum' . (filter even) . (map (^2))
+ squareEvenSum' = evenSum . (map (^2))
+#+END_SRC
+
+We just had to add another "transformation function"[^0216].
+
+#+BEGIN_EXAMPLE
+ map (^2) [1,2,3,4] ⇔ [1,4,9,16]
+#+END_EXAMPLE
+
+The =map= function simply applies a function to all the elements of a
+list.
+
+We didn't have to modify anything /inside/ the function definition. This
+makes the code more modular. But in addition you can think more
+mathematically about your function. You can also use your function
+interchangably with others, as needed. That is, you can compose, map,
+fold, filter using your new function.
+
+Modifying version 1 is left as an exercise to the reader ☺.
+
+If you believe we have reached the end of generalization, then know you
+are very wrong. For example, there is a way to not only use this
+function on lists but on any recursive type. If you want to know how, I
+suggest you to read this quite fun article:
+[[http://eprints.eemcs.utwente.nl/7281/01/db-utwente-40501F46.pdf][Functional
+Programming with Bananas, Lenses, Envelopes and Barbed Wire by Meijer,
+Fokkinga and Paterson]].
+
+This example should show you how great pure functional programming is.
+Unfortunately, using pure functional programming isn't well suited to
+all usages. Or at least such a language hasn't been found yet.
+
+One of the great powers of Haskell is the ability to create DSLs (Domain
+Specific Language) making it easy to change the programming paradigm.
+
+In fact, Haskell is also great when you want to write imperative style
+programming. Understanding this was really hard for me to grasp when
+first learning Haskell. A lot of effort tends to go into explaining the
+superiority of the functional approach. Then when you start using an
+imperative style with Haskell, it can be hard to understand when and how
+to use it.
+
+But before talking about this Haskell super-power, we must talk about
+another essential aspect of Haskell: /Types/.
+
+#+BEGIN_SRC haskell :eval never-export
+ main = print $ evenSum [1..10]
+#+END_SRC
+
+02_Hard_Part/16_Functions.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Types
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+blogimage("salvador-dali-the-madonna-of-port-lligat.jpg","Dali, the
+madonna of port Lligat")
+
+#+BEGIN_QUOTE
+ %tldr
+
+ - =type Name = AnotherType= is just an alias and the compiler doesn't
+ mark any difference between =Name= and =AnotherType=.
+ - =data Name = NameConstructor AnotherType= does mark a difference.
+ - =data= can construct structures which can be recursives.
+ - =deriving= is magic and creates functions for you.
+#+END_QUOTE
+
+In Haskell, types are strong and static.
+
+Why is this important? It will help you /greatly/ to avoid mistakes. In
+Haskell, most bugs are caught during the compilation of your program.
+And the main reason is because of the type inference during compilation.
+Type inference makes it easy to detect where you used the wrong
+parameter at the wrong place, for example.
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Type inference
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Static typing is generally essential for fast execution. But most
+statically typed languages are bad at generalizing concepts. Haskell's
+saving grace is that it can /infer/ types.
+
+Here is a simple example, the =square= function in Haskell:
+
+#+BEGIN_SRC haskell :eval never-export
+ square x = x * x
+#+END_SRC
+
+This function can =square= any Numeral type. You can provide =square=
+with an =Int=, an =Integer=, a =Float= a =Fractional= and even
+=Complex=. Proof by example:
+
+#+BEGIN_EXAMPLE
+ % ghci
+ GHCi, version 7.0.4:
+ ...
+ Prelude> let square x = x*x
+ Prelude> square 2
+ 4
+ Prelude> square 2.1
+ 4.41
+ Prelude> -- load the Data.Complex module
+ Prelude> :m Data.Complex
+ Prelude Data.Complex> square (2 :+ 1)
+ 3.0 :+ 4.0
+#+END_EXAMPLE
+
+=x :+ y= is the notation for the complex (x + iy).
+
+Now compare with the amount of code necessary in C:
+
+#+BEGIN_SRC C
+ int int_square(int x) { return x*x; }
+
+ float float_square(float x) {return x*x; }
+
+ complex complex_square (complex z) {
+ complex tmp;
+ tmp.real = z.real * z.real - z.img * z.img;
+ tmp.img = 2 * z.img * z.real;
+ }
+
+ complex x,y;
+ y = complex_square(x);
+#+END_SRC
+
+For each type, you need to write a new function. The only way to work
+around this problem is to use some meta-programming trick, for example
+using the pre-processor. In C++ there is a better way, C++ templates:
+
+#+BEGIN_EXAMPLE
+ #include
+ #include
+ using namespace std;
+
+ template
+ T square(T x)
+ {
+ return x*x;
+ }
+
+ int main() {
+ // int
+ int sqr_of_five = square(5);
+ cout << sqr_of_five << endl;
+ // double
+ cout << (double)square(5.3) << endl;
+ // complex
+ cout << square( complex(5,3) )
+ << endl;
+ return 0;
+ }
+#+END_EXAMPLE
+
+C++ does a far better job than C in this regard. But for more complex
+functions the syntax can be hard to follow: see
+[[http://bartoszmilewski.com/2009/10/21/what-does-haskell-have-to-do-with-c/][this
+article]] for example.
+
+In C++ you must declare that a function can work with different types.
+In Haskell, the opposite is the case. The function will be as general as
+possible by default.
+
+Type inference gives Haskell the feeling of freedom that dynamically
+typed languages provide. But unlike dynamically typed languages, most
+errors are caught before run time. Generally, in Haskell:
+
+#+BEGIN_QUOTE
+ "if it compiles it certainly does what you intended"
+#+END_QUOTE
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/21_Types.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Type construction
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+You can construct your own types. First, you can use aliases or type
+synonyms.
+
+#+BEGIN_SRC haskell :eval never-export
+ type Name = String
+ type Color = String
+
+ showInfos :: Name -> Color -> String
+ showInfos name color = "Name: " ++ name
+ ++ ", Color: " ++ color
+ name :: Name
+ name = "Robin"
+ color :: Color
+ color = "Blue"
+ main = putStrLn $ showInfos name color
+#+END_SRC
+
+02_Hard_Part/21_Types.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/22_Types.lhs
+
+But it doesn't protect you much. Try to swap the two parameter of
+=showInfos= and run the program:
+
+#+BEGIN_SRC haskell :eval never-export
+ putStrLn $ showInfos color name
+#+END_SRC
+
+It will compile and execute. In fact you can replace Name, Color and
+String everywhere. The compiler will treat them as completely identical.
+
+Another method is to create your own types using the keyword =data=.
+
+#+BEGIN_SRC haskell :eval never-export
+ data Name = NameConstr String
+ data Color = ColorConstr String
+
+ showInfos :: Name -> Color -> String
+ showInfos (NameConstr name) (ColorConstr color) =
+ "Name: " ++ name ++ ", Color: " ++ color
+
+ name = NameConstr "Robin"
+ color = ColorConstr "Blue"
+ main = putStrLn $ showInfos name color
+#+END_SRC
+
+Now if you switch parameters of =showInfos=, the compiler complains! So
+this is a potential mistake you will never make again and the only price
+is to be more verbose.
+
+Also notice that constructors are functions:
+
+#+BEGIN_SRC haskell :eval never-export
+ NameConstr :: String -> Name
+ ColorConstr :: String -> Color
+#+END_SRC
+
+The syntax of =data= is mainly:
+
+#+BEGIN_SRC haskell :eval never-export
+ data TypeName = ConstructorName [types]
+ | ConstructorName2 [types]
+ | ...
+#+END_SRC
+
+Generally the usage is to use the same name for the DataTypeName and
+DataTypeConstructor.
+
+Example:
+
+#+BEGIN_SRC haskell :eval never-export
+ data Complex a = Num a => Complex a a
+#+END_SRC
+
+Also you can use the record syntax:
+
+#+BEGIN_SRC haskell :eval never-export
+ data DataTypeName = DataConstructor {
+ field1 :: [type of field1]
+ , field2 :: [type of field2]
+ ...
+ , fieldn :: [type of fieldn] }
+#+END_SRC
+
+And many accessors are made for you. Furthermore you can use another
+order when setting values.
+
+Example:
+
+#+BEGIN_SRC haskell :eval never-export
+ data Complex a = Num a => Complex { real :: a, img :: a}
+ c = Complex 1.0 2.0
+ z = Complex { real = 3, img = 4 }
+ real c ⇒ 1.0
+ img z ⇒ 4
+#+END_SRC
+
+02_Hard_Part/22_Types.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/23_Types.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Recursive type
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+You already encountered a recursive type: lists. You can re-create
+lists, but with a more verbose syntax:
+
+#+BEGIN_SRC haskell :eval never-export
+ data List a = Empty | Cons a (List a)
+#+END_SRC
+
+If you really want to use an easier syntax you can use an infix name for
+constructors.
+
+#+BEGIN_SRC haskell :eval never-export
+ infixr 5 :::
+ data List a = Nil | a ::: (List a)
+#+END_SRC
+
+The number after =infixr= gives the precedence.
+
+If you want to be able to print (=Show=), read (=Read=), test equality
+(=Eq=) and compare (=Ord=) your new data structure you can tell Haskell
+to derive the appropriate functions for you.
+
+#+BEGIN_SRC haskell :eval never-export
+ infixr 5 :::
+ data List a = Nil | a ::: (List a)
+ deriving (Show,Read,Eq,Ord)
+#+END_SRC
+
+When you add =deriving (Show)= to your data declaration, Haskell creates
+a =show= function for you. We'll see soon how you can use your own
+=show= function.
+
+#+BEGIN_SRC haskell :eval never-export
+ convertList [] = Nil
+ convertList (x:xs) = x ::: convertList xs
+#+END_SRC
+
+#+BEGIN_SRC haskell :eval never-export
+ main = do
+ print (0 ::: 1 ::: Nil)
+ print (convertList [0,1])
+#+END_SRC
+
+This prints:
+
+#+BEGIN_EXAMPLE
+ 0 ::: (1 ::: Nil)
+ 0 ::: (1 ::: Nil)
+#+END_EXAMPLE
+
+02_Hard_Part/23_Types.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/30_Trees.lhs
+
+*** Trees
+ :PROPERTIES:
+ :CUSTOM_ID: trees
+ :END:
+
+blogimage("magritte-l-arbre.jpg","Magritte, l'Arbre")
+
+We'll just give another standard example: binary trees.
+
+#+BEGIN_SRC haskell :eval never-export
+ import Data.List
+
+ data BinTree a = Empty
+ | Node a (BinTree a) (BinTree a)
+ deriving (Show)
+#+END_SRC
+
+We will also create a function which turns a list into an ordered binary
+tree.
+
+#+BEGIN_SRC haskell :eval never-export
+ treeFromList :: (Ord a) => [a] -> BinTree a
+ treeFromList [] = Empty
+ treeFromList (x:xs) = Node x (treeFromList (filter (x) xs))
+#+END_SRC
+
+Look at how elegant this function is. In plain English:
+
+- an empty list will be converted to an empty tree.
+- a list =(x:xs)= will be converted to a tree where:
+
+ - The root is =x=
+ - Its left subtree is the tree created from members of the list =xs=
+ which are strictly inferior to =x= and
+ - the right subtree is the tree created from members of the list =xs=
+ which are strictly superior to =x=.
+
+#+BEGIN_SRC haskell :eval never-export
+ main = print $ treeFromList [7,2,4,8]
+#+END_SRC
+
+You should obtain the following:
+
+#+BEGIN_EXAMPLE
+ Node 7 (Node 2 Empty (Node 4 Empty Empty)) (Node 8 Empty Empty)
+#+END_EXAMPLE
+
+This is an informative but quite unpleasant representation of our tree.
+
+02_Hard_Part/30_Trees.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/31_Trees.lhs
+
+Just for fun, let's code a better display for our trees. I simply had
+fun making a nice function to display trees in a general way. You can
+safely skip this part if you find it too difficult to follow.
+
+We have a few changes to make. We remove the =deriving (Show)= from the
+declaration of our =BinTree= type. And it might also be useful to make
+our BinTree an instance of (=Eq= and =Ord=) so we will be able to test
+equality and compare trees.
+
+#+BEGIN_SRC haskell :eval never-export
+ data BinTree a = Empty
+ | Node a (BinTree a) (BinTree a)
+ deriving (Eq,Ord)
+#+END_SRC
+
+Without the =deriving (Show)=, Haskell doesn't create a =show= method
+for us. We will create our own version of =show=. To achieve this, we
+must declare that our newly created type =BinTree a= is an instance of
+the type class =Show=. The general syntax is:
+
+#+BEGIN_SRC haskell :eval never-export
+ instance Show (BinTree a) where
+ show t = ... -- You declare your function here
+#+END_SRC
+
+Here is my version of how to show a binary tree. Don't worry about the
+apparent complexity. I made a lot of improvements in order to display
+even stranger objects.
+
+#+BEGIN_SRC haskell :eval never-export
+ -- declare BinTree a to be an instance of Show
+ instance (Show a) => Show (BinTree a) where
+ -- will start by a '<' before the root
+ -- and put a : a begining of line
+ show t = "< " ++ replace '\n' "\n: " (treeshow "" t)
+ where
+ -- treeshow pref Tree
+ -- shows a tree and starts each line with pref
+ -- We don't display the Empty tree
+ treeshow pref Empty = ""
+ -- Leaf
+ treeshow pref (Node x Empty Empty) =
+ (pshow pref x)
+
+ -- Right branch is empty
+ treeshow pref (Node x left Empty) =
+ (pshow pref x) ++ "\n" ++
+ (showSon pref "`--" " " left)
+
+ -- Left branch is empty
+ treeshow pref (Node x Empty right) =
+ (pshow pref x) ++ "\n" ++
+ (showSon pref "`--" " " right)
+
+ -- Tree with left and right children non empty
+ treeshow pref (Node x left right) =
+ (pshow pref x) ++ "\n" ++
+ (showSon pref "|--" "| " left) ++ "\n" ++
+ (showSon pref "`--" " " right)
+
+ -- shows a tree using some prefixes to make it nice
+ showSon pref before next t =
+ pref ++ before ++ treeshow (pref ++ next) t
+
+ -- pshow replaces "\n" by "\n"++pref
+ pshow pref x = replace '\n' ("\n"++pref) (show x)
+
+ -- replaces one char by another string
+ replace c new string =
+ concatMap (change c new) string
+ where
+ change c new x
+ | x == c = new
+ | otherwise = x:[] -- "x"
+#+END_SRC
+
+The =treeFromList= method remains identical.
+
+#+BEGIN_SRC haskell :eval never-export
+ treeFromList :: (Ord a) => [a] -> BinTree a
+ treeFromList [] = Empty
+ treeFromList (x:xs) = Node x (treeFromList (filter (x) xs))
+#+END_SRC
+
+And now, we can play:
+
+#+BEGIN_SRC haskell :eval never-export
+ main = do
+ putStrLn "Int binary tree:"
+ print $ treeFromList [7,2,4,8,1,3,6,21,12,23]
+#+END_SRC
+
+#+BEGIN_EXAMPLE
+ Int binary tree:
+ < 7
+ : |--2
+ : | |--1
+ : | `--4
+ : | |--3
+ : | `--6
+ : `--8
+ : `--21
+ : |--12
+ : `--23
+#+END_EXAMPLE
+
+Now it is far better! The root is shown by starting the line with the
+=<= character. And each following line starts with a =:=. But we could
+also use another type.
+
+#+BEGIN_SRC haskell :eval never-export
+ putStrLn "\nString binary tree:"
+ print $ treeFromList ["foo","bar","baz","gor","yog"]
+#+END_SRC
+
+#+BEGIN_EXAMPLE
+ String binary tree:
+ < "foo"
+ : |--"bar"
+ : | `--"baz"
+ : `--"gor"
+ : `--"yog"
+#+END_EXAMPLE
+
+As we can test equality and order trees, we can make tree of trees!
+
+#+BEGIN_SRC haskell :eval never-export
+ putStrLn "\nBinary tree of Char binary trees:"
+ print ( treeFromList
+ (map treeFromList ["baz","zara","bar"]))
+#+END_SRC
+
+#+BEGIN_EXAMPLE
+ Binary tree of Char binary trees:
+ < < 'b'
+ : : |--'a'
+ : : `--'z'
+ : |--< 'b'
+ : | : |--'a'
+ : | : `--'r'
+ : `--< 'z'
+ : : `--'a'
+ : : `--'r'
+#+END_EXAMPLE
+
+This is why I chose to prefix each line of tree display by =:= (except
+for the root).
+
+blogimage("yo_dawg_tree.jpg","Yo Dawg Tree")
+
+#+BEGIN_SRC haskell :eval never-export
+ putStrLn "\nTree of Binary trees of Char binary trees:"
+ print $ (treeFromList . map (treeFromList . map treeFromList))
+ [ ["YO","DAWG"]
+ , ["I","HEARD"]
+ , ["I","HEARD"]
+ , ["YOU","LIKE","TREES"] ]
+#+END_SRC
+
+Which is equivalent to
+
+#+BEGIN_SRC haskell :eval never-export
+ print ( treeFromList (
+ map treeFromList
+ [ map treeFromList ["YO","DAWG"]
+ , map treeFromList ["I","HEARD"]
+ , map treeFromList ["I","HEARD"]
+ , map treeFromList ["YOU","LIKE","TREES"] ]))
+#+END_SRC
+
+and gives:
+
+#+BEGIN_EXAMPLE
+ Binary tree of Binary trees of Char binary trees:
+ < < < 'Y'
+ : : : `--'O'
+ : : `--< 'D'
+ : : : |--'A'
+ : : : `--'W'
+ : : : `--'G'
+ : |--< < 'I'
+ : | : `--< 'H'
+ : | : : |--'E'
+ : | : : | `--'A'
+ : | : : | `--'D'
+ : | : : `--'R'
+ : `--< < 'Y'
+ : : : `--'O'
+ : : : `--'U'
+ : : `--< 'L'
+ : : : `--'I'
+ : : : |--'E'
+ : : : `--'K'
+ : : `--< 'T'
+ : : : `--'R'
+ : : : |--'E'
+ : : : `--'S'
+#+END_EXAMPLE
+
+Notice how duplicate trees aren't inserted; there is only one tree
+corresponding to ="I","HEARD"=. We have this for (almost) free, because
+we have declared Tree to be an instance of =Eq=.
+
+See how awesome this structure is: We can make trees containing not only
+integers, strings and chars, but also other trees. And we can even make
+a tree containing a tree of trees!
+
+02_Hard_Part/31_Trees.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/40_Infinites_Structures.lhs
+
+** Infinite Structures
+ :PROPERTIES:
+ :CUSTOM_ID: infinite-structures
+ :END:
+
+blogimage("escher_infinite_lizards.jpg","Escher")
+
+It is often said that Haskell is /lazy/.
+
+In fact, if you are a bit pedantic, you should say that
+[[http://www.haskell.org/haskellwiki/Lazy_vs._non-strict][Haskell is
+/non-strict/]]. Laziness is just a common implementation for non-strict
+languages.
+
+Then what does "not-strict" mean? From the Haskell wiki:
+
+#+BEGIN_QUOTE
+ Reduction (the mathematical term for evaluation) proceeds from the
+ outside in.
+
+ so if you have =(a+(b*c))= then you first reduce =+= first, then you
+ reduce the inner =(b*c)=
+#+END_QUOTE
+
+For example in Haskell you can do:
+
+#+BEGIN_SRC haskell :eval never-export
+ -- numbers = [1,2,..]
+ numbers :: [Integer]
+ numbers = 0:map (1+) numbers
+
+ take' n [] = []
+ take' 0 l = []
+ take' n (x:xs) = x:take' (n-1) xs
+
+ main = print $ take' 10 numbers
+#+END_SRC
+
+And it stops.
+
+How?
+
+Instead of trying to evaluate =numbers= entirely, it evaluates elements
+only when needed.
+
+Also, note in Haskell there is a notation for infinite lists
+
+#+BEGIN_EXAMPLE
+ [1..] ⇔ [1,2,3,4...]
+ [1,3..] ⇔ [1,3,5,7,9,11...]
+#+END_EXAMPLE
+
+and most functions will work with them. Also, there is a built-in
+function =take= which is equivalent to our =take'=.
+
+02_Hard_Part/40_Infinites_Structures.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+02_Hard_Part/41_Infinites_Structures.lhs
+
+This code is mostly the same as the previous one.
+
+#+BEGIN_SRC haskell :eval never-export
+ import Debug.Trace (trace)
+ import Data.List
+ data BinTree a = Empty
+ | Node a (BinTree a) (BinTree a)
+ deriving (Eq,Ord)
+#+END_SRC
+
+#+BEGIN_SRC haskell :eval never-export
+ -- declare BinTree a to be an instance of Show
+ instance (Show a) => Show (BinTree a) where
+ -- will start by a '<' before the root
+ -- and put a : a begining of line
+ show t = "< " ++ replace '\n' "\n: " (treeshow "" t)
+ where
+ treeshow pref Empty = ""
+ treeshow pref (Node x Empty Empty) =
+ (pshow pref x)
+
+ treeshow pref (Node x left Empty) =
+ (pshow pref x) ++ "\n" ++
+ (showSon pref "`--" " " left)
+
+ treeshow pref (Node x Empty right) =
+ (pshow pref x) ++ "\n" ++
+ (showSon pref "`--" " " right)
+
+ treeshow pref (Node x left right) =
+ (pshow pref x) ++ "\n" ++
+ (showSon pref "|--" "| " left) ++ "\n" ++
+ (showSon pref "`--" " " right)
+
+ -- show a tree using some prefixes to make it nice
+ showSon pref before next t =
+ pref ++ before ++ treeshow (pref ++ next) t
+
+ -- pshow replace "\n" by "\n"++pref
+ pshow pref x = replace '\n' ("\n"++pref) (" " ++ show x)
+
+ -- replace on char by another string
+ replace c new string =
+ concatMap (change c new) string
+ where
+ change c new x
+ | x == c = new
+ | otherwise = x:[] -- "x"
+#+END_SRC
+
+Suppose we don't mind having an ordered binary tree. Here is an infinite
+binary tree:
+
+#+BEGIN_SRC haskell :eval never-export
+ nullTree = Node 0 nullTree nullTree
+#+END_SRC
+
+A complete binary tree where each node is equal to 0. Now I will prove
+you can manipulate this object using the following function:
+
+#+BEGIN_SRC haskell :eval never-export
+ -- take all element of a BinTree
+ -- up to some depth
+ treeTakeDepth _ Empty = Empty
+ treeTakeDepth 0 _ = Empty
+ treeTakeDepth n (Node x left right) = let
+ nl = treeTakeDepth (n-1) left
+ nr = treeTakeDepth (n-1) right
+ in
+ Node x nl nr
+#+END_SRC
+
+See what occurs for this program:
+
+#+BEGIN_SRC haskell :eval never-export
+ main = print $ treeTakeDepth 4 nullTree
+#+END_SRC
+
+This code compiles, runs and stops giving the following result:
+
+#+BEGIN_EXAMPLE
+ < 0
+ : |-- 0
+ : | |-- 0
+ : | | |-- 0
+ : | | `-- 0
+ : | `-- 0
+ : | |-- 0
+ : | `-- 0
+ : `-- 0
+ : |-- 0
+ : | |-- 0
+ : | `-- 0
+ : `-- 0
+ : |-- 0
+ : `-- 0
+#+END_EXAMPLE
+
+Just to heat up your neurones a bit more, let's make a slightly more
+interesting tree:
+
+#+BEGIN_SRC haskell :eval never-export
+ iTree = Node 0 (dec iTree) (inc iTree)
+ where
+ dec (Node x l r) = Node (x-1) (dec l) (dec r)
+ inc (Node x l r) = Node (x+1) (inc l) (inc r)
+#+END_SRC
+
+Another way to create this tree is to use a higher order function. This
+function should be similar to =map=, but should work on =BinTree=
+instead of list. Here is such a function:
+
+#+BEGIN_SRC haskell :eval never-export
+ -- apply a function to each node of Tree
+ treeMap :: (a -> b) -> BinTree a -> BinTree b
+ treeMap f Empty = Empty
+ treeMap f (Node x left right) = Node (f x)
+ (treeMap f left)
+ (treeMap f right)
+#+END_SRC
+
+/Hint/: I won't talk more about this here. If you are interested in the
+generalization of =map= to other data structures, search for functor and
+=fmap=.
+
+Our definition is now:
+
+#+BEGIN_SRC haskell :eval never-export
+ infTreeTwo :: BinTree Int
+ infTreeTwo = Node 0 (treeMap (\x -> x-1) infTreeTwo)
+ (treeMap (\x -> x+1) infTreeTwo)
+#+END_SRC
+
+Look at the result for
+
+#+BEGIN_SRC haskell :eval never-export
+ main = print $ treeTakeDepth 4 infTreeTwo
+#+END_SRC
+
+#+BEGIN_EXAMPLE
+ < 0
+ : |-- -1
+ : | |-- -2
+ : | | |-- -3
+ : | | `-- -1
+ : | `-- 0
+ : | |-- -1
+ : | `-- 1
+ : `-- 1
+ : |-- 0
+ : | |-- -1
+ : | `-- 1
+ : `-- 2
+ : |-- 1
+ : `-- 3
+#+END_EXAMPLE
+
+#+BEGIN_SRC haskell :eval never-export
+ main = do
+ print $ treeTakeDepth 4 nullTree
+ print $ treeTakeDepth 4 infTreeTwo
+#+END_SRC
+
+02_Hard_Part/41_Infinites_Structures.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Hell Difficulty Part
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Congratulations for getting so far! Now, some of the really hardcore
+stuff can start.
+
+If you are like me, you should get the functional style. You should also
+understand a bit more the advantages of laziness by default. But you
+also don't really understand where to start in order to make a real
+program. And in particular:
+
+- How do you deal with effects?
+- Why is there a strange imperative-like notation for dealing with IO?
+
+Be prepared, the answers might be complex. But they are all very
+rewarding.
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+03_Hell/01_IO/01_progressive_io_example.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Deal With IO
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+blogimage("magritte_carte_blanche.jpg","Magritte, Carte blanche")
+
+#+BEGIN_QUOTE
+ %tldr
+
+ A typical function doing =IO= looks a lot like an imperative program:
+
+ #+BEGIN_EXAMPLE
+ f :: IO a
+ f = do
+ x <- action1
+ action2 x
+ y <- action3
+ action4 x y
+ #+END_EXAMPLE
+
+ - To set a value to an object we use =<-= .
+ - The type of each line is =IO *=; in this example:
+
+ - =action1 :: IO b=
+ - =action2 x :: IO ()=
+ - =action3 :: IO c=
+ - =action4 x y :: IO a=
+ - =x :: b=, =y :: c=
+
+ - Few objects have the type =IO a=, this should help you choose. In
+ particular you cannot use pure functions directly here. To use pure
+ functions you could do =action2 (purefunction x)= for example.
+#+END_QUOTE
+
+In this section, I will explain how to use IO, not how it works. You'll
+see how Haskell separates the pure from the impure parts of the program.
+
+Don't stop because you're trying to understand the details of the
+syntax. Answers will come in the next section.
+
+What to achieve?
+
+#+BEGIN_QUOTE
+ Ask a user to enter a list of numbers. Print the sum of the numbers
+#+END_QUOTE
+
+#+BEGIN_SRC haskell :eval never-export
+ toList :: String -> [Integer]
+ toList input = read ("[" ++ input ++ "]")
+
+ main = do
+ putStrLn "Enter a list of numbers (separated by comma):"
+ input <- getLine
+ print $ sum (toList input)
+#+END_SRC
+
+It should be straightforward to understand the behavior of this program.
+Let's analyze the types in more detail.
+
+#+BEGIN_EXAMPLE
+ putStrLn :: String -> IO ()
+ getLine :: IO String
+ print :: Show a => a -> IO ()
+#+END_EXAMPLE
+
+Or more interestingly, we note that each expression in the =do= block
+has a type of =IO a=.
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+We should also pay attention to the effect of the =<-= symbol.
+
+#+BEGIN_EXAMPLE
+ do
+ x <- something
+#+END_EXAMPLE
+
+If =something :: IO a= then =x :: a=.
+
+Another important note about using =IO=: All lines in a do block must be
+of one of the two forms:
+
+#+BEGIN_EXAMPLE
+ action1 :: IO a
+ -- in this case, generally a = ()
+#+END_EXAMPLE
+
+ou
+
+#+BEGIN_EXAMPLE
+ value <- action2 -- where
+ -- action2 :: IO b
+ -- value :: b
+#+END_EXAMPLE
+
+These two kinds of line will correspond to two different ways of
+sequencing actions. The meaning of this sentence should be clearer by
+the end of the next section.
+
+03_Hell/01_IO/01_progressive_io_example.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+03_Hell/01_IO/02_progressive_io_example.lhs
+
+Now let's see how this program behaves. For example, what happens if the
+user enters something strange? Let's try:
+
+#+BEGIN_EXAMPLE
+ % runghc 02_progressive_io_example.lhs
+ Enter a list of numbers (separated by comma):
+ foo
+ Prelude.read: no parse
+#+END_EXAMPLE
+
+Argh! An evil error message and a crash! Our first improvement will
+simply be to answer with a more friendly message.
+
+In order to do this, we must detect that something went wrong. Here is
+one way to do this: use the type =Maybe=. This is a very common type in
+Haskell.
+
+#+BEGIN_SRC haskell :eval never-export
+ import Data.Maybe
+#+END_SRC
+
+What is this thing? =Maybe= is a type which takes one parameter. Its
+definition is:
+
+#+BEGIN_SRC haskell :eval never-export
+ data Maybe a = Nothing | Just a
+#+END_SRC
+
+This is a nice way to tell there was an error while trying to
+create/compute a value. The =maybeRead= function is a great example of
+this. This is a function similar to the function =read=[fn:4], but if
+something goes wrong the returned value is =Nothing=. If the value is
+right, it returns =Just =. Don't try to understand too much
+of this function. I use a lower level function than =read=: =reads=.
+
+#+BEGIN_SRC haskell :eval never-export
+ maybeRead :: Read a => String -> Maybe a
+ maybeRead s = case reads s of
+ [(x,"")] -> Just x
+ _ -> Nothing
+#+END_SRC
+
+Now to be a bit more readable, we define a function which goes like
+this: If the string has the wrong format, it will return =Nothing=.
+Otherwise, for example for "1,2,3", it will return =Just [1,2,3]=.
+
+#+BEGIN_SRC haskell :eval never-export
+ getListFromString :: String -> Maybe [Integer]
+ getListFromString str = maybeRead $ "[" ++ str ++ "]"
+#+END_SRC
+
+We simply have to test the value in our main function.
+
+#+BEGIN_SRC haskell :eval never-export
+ main :: IO ()
+ main = do
+ putStrLn "Enter a list of numbers (separated by comma):"
+ input <- getLine
+ let maybeList = getListFromString input in
+ case maybeList of
+ Just l -> print (sum l)
+ Nothing -> error "Bad format. Good Bye."
+#+END_SRC
+
+In case of error, we display a nice error message.
+
+Note that the type of each expression in the main's =do= block remains
+of the form =IO a=. The only strange construction is =error=. I'll just
+say here that =error msg= takes the needed type (here =IO ()=).
+
+One very important thing to note is the type of all the functions
+defined so far. There is only one function which contains =IO= in its
+type: =main=. This means main is impure. But main uses
+=getListFromString= which is pure. So it's clear just by looking at
+declared types which functions are pure and which are impure.
+
+Why does purity matter? Among the many advantages, here are three:
+
+- It is far easier to think about pure code than impure code.
+- Purity protects you from all the hard-to-reproduce bugs that are due
+ to side effects.
+- You can evaluate pure functions in any order or in parallel without
+ risk.
+
+This is why you should generally put as most code as possible inside
+pure functions.
+
+03_Hell/01_IO/02_progressive_io_example.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+03_Hell/01_IO/03_progressive_io_example.lhs
+
+Our next iteration will be to prompt the user again and again until she
+enters a valid answer.
+
+We keep the first part:
+
+#+BEGIN_SRC haskell :eval never-export
+ import Data.Maybe
+
+ maybeRead :: Read a => String -> Maybe a
+ maybeRead s = case reads s of
+ [(x,"")] -> Just x
+ _ -> Nothing
+ getListFromString :: String -> Maybe [Integer]
+ getListFromString str = maybeRead $ "[" ++ str ++ "]"
+#+END_SRC
+
+Now we create a function which will ask the user for an list of integers
+until the input is right.
+
+#+BEGIN_SRC haskell :eval never-export
+ askUser :: IO [Integer]
+ askUser = do
+ putStrLn "Enter a list of numbers (separated by comma):"
+ input <- getLine
+ let maybeList = getListFromString input in
+ case maybeList of
+ Just l -> return l
+ Nothing -> askUser
+#+END_SRC
+
+This function is of type =IO [Integer]=. Such a type means that we
+retrieved a value of type =[Integer]= through some IO actions. Some
+people might explain while waving their hands:
+
+#+BEGIN_QUOTE
+ «This is an =[Integer]= inside an =IO=»
+#+END_QUOTE
+
+If you want to understand the details behind all of this, you'll have to
+read the next section. But really, if you just want to /use/ IO just
+practice a little and remember to think about the type.
+
+Finally our main function is much simpler:
+
+#+BEGIN_SRC haskell :eval never-export
+ main :: IO ()
+ main = do
+ list <- askUser
+ print $ sum list
+#+END_SRC
+
+We have finished with our introduction to =IO=. This was quite fast.
+Here are the main things to remember:
+
+- in the =do= block, each expression must have the type =IO a=. You are
+ then limited with regard to the range of expressions available. For
+ example, =getLine=, =print=, =putStrLn=, etc...
+- Try to externalize the pure functions as much as possible.
+- the =IO a= type means: an IO /action/ which returns an element of type
+ =a=. =IO= represents actions; under the hood, =IO a= is the type of a
+ function. Read the next section if you are curious.
+
+If you practice a bit, you should be able to /use/ =IO=.
+
+#+BEGIN_QUOTE
+ /Exercises/:
+
+ - Make a program that sums all of its arguments. Hint: use the
+ function =getArgs=.
+#+END_QUOTE
+
+03_Hell/01_IO/03_progressive_io_example.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+blogimage("magritte_pipe.jpg","Magritte, ceci n'est pas une pipe")
+
+#+BEGIN_QUOTE
+ Here is a %tldr for this section.
+
+ To separate pure and impure parts, =main= is defined as a function
+ which modifies the state of the world.
+
+ #+BEGIN_EXAMPLE
+ main :: World -> World
+ #+END_EXAMPLE
+
+ A function is guaranteed to have side effects only if it has this
+ type. But look at a typical main function:
+
+ #+BEGIN_EXAMPLE
+
+ main w0 =
+ let (v1,w1) = action1 w0 in
+ let (v2,w2) = action2 v1 w1 in
+ let (v3,w3) = action3 v2 w2 in
+ action4 v3 w3
+ #+END_EXAMPLE
+
+ We have a lot of temporary elements (here =w1=, =w2= and =w3=) which
+ must be passed on to the next action.
+
+ We create a function =bind= or =(>>=)=. With =bind= we don't need
+ temporary names anymore.
+
+ #+BEGIN_EXAMPLE
+ main =
+ action1 >>= action2 >>= action3 >>= action4
+ #+END_EXAMPLE
+
+ Bonus: Haskell has syntactical sugar for us:
+
+ #+BEGIN_EXAMPLE
+ main = do
+ v1 <- action1
+ v2 <- action2 v1
+ v3 <- action3 v2
+ action4 v3
+ #+END_EXAMPLE
+#+END_QUOTE
+
+Why did we use this strange syntax, and what exactly is this =IO= type?
+It looks a bit like magic.
+
+For now let's just forget all about the pure parts of our program, and
+focus on the impure parts:
+
+#+BEGIN_SRC haskell :eval never-export
+ askUser :: IO [Integer]
+ askUser = do
+ putStrLn "Enter a list of numbers (separated by commas):"
+ input <- getLine
+ let maybeList = getListFromString input in
+ case maybeList of
+ Just l -> return l
+ Nothing -> askUser
+
+ main :: IO ()
+ main = do
+ list <- askUser
+ print $ sum list
+#+END_SRC
+
+First remark: this looks imperative. Haskell is powerful enough to make
+impure code look imperative. For example, if you wish you could create a
+=while= in Haskell. In fact, for dealing with =IO=, an imperative style
+is generally more appropriate.
+
+But you should have noticed that the notation is a bit unusual. Here is
+why, in detail.
+
+In an impure language, the state of the world can be seen as a huge
+hidden global variable. This hidden variable is accessible by all
+functions of your language. For example, you can read and write a file
+in any function. Whether a file exists or not is a difference in the
+possible states that the world can take.
+
+In Haskell the current state of the world is not hidden. Rather, it is
+/explicitly/ said that =main= is a function that /potentially/ changes
+the state of the world. Its type is then something like:
+
+#+BEGIN_SRC haskell :eval never-export
+ main :: World -> World
+#+END_SRC
+
+Not all functions may access this variable. Those which have access to
+this variable are impure. Functions to which the world variable isn't
+provided are pure[fn:5].
+
+Haskell considers the state of the world as an input variable to =main=.
+But the real type of main is closer to this one[fn:6]:
+
+#+BEGIN_SRC haskell :eval never-export
+ main :: World -> ((),World)
+#+END_SRC
+
+The =()= type is the unit type. Nothing to see here.
+
+Now let's rewrite our main function with this in mind:
+
+#+BEGIN_SRC haskell :eval never-export
+ main w0 =
+ let (list,w1) = askUser w0 in
+ let (x,w2) = print (sum list,w1) in
+ x
+#+END_SRC
+
+First, we note that all functions which have side effects must have the
+type:
+
+#+BEGIN_SRC haskell :eval never-export
+ World -> (a,World)
+#+END_SRC
+
+where =a= is the type of the result. For example, a =getChar= function
+should have the type =World -> (Char, World)=.
+
+Another thing to note is the trick to fix the order of evaluation. In
+Haskell, in order to evaluate =f a b=, you have many choices:
+
+- first eval =a= then =b= then =f a b=
+- first eval =b= then =a= then =f a b=.
+- eval =a= and =b= in parallel then =f a b=
+
+This is true because we're working in a pure part of the language.
+
+Now, if you look at the main function, it is clear you must eval the
+first line before the second one since to evaluate the second line you
+have to get a parameter given by the evaluation of the first line.
+
+This trick works like a charm. The compiler will at each step provide a
+pointer to a new real world id. Under the hood, =print= will evaluate
+as:
+
+- print something on the screen
+- modify the id of the world
+- evaluate as =((),new world id)=.
+
+Now, if you look at the style of the main function, it is clearly
+awkward. Let's try to do the same to the =askUser= function:
+
+#+BEGIN_SRC haskell :eval never-export
+ askUser :: World -> ([Integer],World)
+#+END_SRC
+
+Before:
+
+#+BEGIN_SRC haskell :eval never-export
+ askUser :: IO [Integer]
+ askUser = do
+ putStrLn "Enter a list of numbers:"
+ input <- getLine
+ let maybeList = getListFromString input in
+ case maybeList of
+ Just l -> return l
+ Nothing -> askUser
+#+END_SRC
+
+After:
+
+#+BEGIN_SRC haskell :eval never-export
+ askUser w0 =
+ let (_,w1) = putStrLn "Enter a list of numbers:" in
+ let (input,w2) = getLine w1 in
+ let (l,w3) = case getListFromString input of
+ Just l -> (l,w2)
+ Nothing -> askUser w2
+ in
+ (l,w3)
+#+END_SRC
+
+This is similar, but awkward. Look at all these temporary =w?= names.
+
+The lesson is: naive IO implementation in Pure functional languages is
+awkward!
+
+Fortunately, there is a better way to handle this problem. We see a
+pattern. Each line is of the form:
+
+#+BEGIN_SRC haskell :eval never-export
+ let (y,w') = action x w in
+#+END_SRC
+
+Even if for some lines the first =x= argument isn't needed. The output
+type is a couple, =(answer, newWorldValue)=. Each function =f= must have
+a type similar to:
+
+#+BEGIN_SRC haskell :eval never-export
+ f :: World -> (a,World)
+#+END_SRC
+
+Not only this, but we can also note that we always follow the same usage
+pattern:
+
+#+BEGIN_SRC haskell :eval never-export
+ let (y,w1) = action1 w0 in
+ let (z,w2) = action2 w1 in
+ let (t,w3) = action3 w2 in
+ ...
+#+END_SRC
+
+Each action can take from 0 to n parameters. And in particular, each
+action can take a parameter from the result of a line above.
+
+For example, we could also have:
+
+#+BEGIN_SRC haskell :eval never-export
+ let (_,w1) = action1 x w0 in
+ let (z,w2) = action2 w1 in
+ let (_,w3) = action3 z w2 in
+ ...
+#+END_SRC
+
+With, of course: =actionN w :: (World) -> (a,World)=.
+
+#+BEGIN_QUOTE
+ IMPORTANT: there are only two important patterns to consider:
+
+ #+BEGIN_EXAMPLE
+ let (x,w1) = action1 w0 in
+ let (y,w2) = action2 x w1 in
+ #+END_EXAMPLE
+
+ and
+
+ #+BEGIN_EXAMPLE
+ let (_,w1) = action1 w0 in
+ let (y,w2) = action2 w1 in
+ #+END_EXAMPLE
+#+END_QUOTE
+
+leftblogimage("jocker_pencil_trick.jpg","Jocker pencil trick")
+
+Now, we will do a magic trick. We will make the temporary world symbols
+"disappear". We will =bind= the two lines. Let's define the =bind=
+function. Its type is quite intimidating at first:
+
+#+BEGIN_SRC haskell :eval never-export
+ bind :: (World -> (a,World))
+ -> (a -> (World -> (b,World)))
+ -> (World -> (b,World))
+#+END_SRC
+
+But remember that =(World -> (a,World))= is the type for an IO action.
+Now let's rename it for clarity:
+
+#+BEGIN_SRC haskell :eval never-export
+ type IO a = World -> (a, World)
+#+END_SRC
+
+Some examples of functions:
+
+#+BEGIN_SRC haskell :eval never-export
+ getLine :: IO String
+ print :: Show a => a -> IO ()
+#+END_SRC
+
+=getLine= is an IO action which takes world as a parameter and returns a
+couple =(String, World)=. This can be summarized as: =getLine= is of
+type =IO String=, which we also see as an IO action which will return a
+String "embeded inside an IO".
+
+The function =print= is also interesting. It takes one argument which
+can be shown. In fact it takes two arguments. The first is the value to
+print and the other is the state of world. It then returns a couple of
+type =((), World)=. This means that it changes the state of the world,
+but doesn't yield any more data.
+
+This new =IO a= type helps us simplify the type of =bind=:
+
+#+BEGIN_SRC haskell :eval never-export
+ bind :: IO a
+ -> (a -> IO b)
+ -> IO b
+#+END_SRC
+
+It says that =bind= takes two IO actions as parameters and returns
+another IO action.
+
+Now, remember the /important/ patterns. The first was:
+
+#+BEGIN_SRC haskell :eval never-export
+ pattern1 w0 =
+ let (x,w1) = action1 w0 in
+ let (y,w2) = action2 x w1 in
+ (y,w2)
+#+END_SRC
+
+Look at the types:
+
+#+BEGIN_SRC haskell :eval never-export
+ action1 :: IO a
+ action2 :: a -> IO b
+ pattern1 :: IO b
+#+END_SRC
+
+Doesn't it seem familiar?
+
+#+BEGIN_SRC haskell :eval never-export
+ (bind action1 action2) w0 =
+ let (x, w1) = action1 w0
+ (y, w2) = action2 x w1
+ in (y, w2)
+#+END_SRC
+
+The idea is to hide the World argument with this function. Let's go: As
+an example imagine if we wanted to simulate:
+
+#+BEGIN_SRC haskell :eval never-export
+ let (line1, w1) = getLine w0 in
+ let ((), w2) = print line1 in
+ ((), w2)
+#+END_SRC
+
+Now, using the =bind= function:
+
+#+BEGIN_SRC haskell :eval never-export
+ (res, w2) = (bind getLine print) w0
+#+END_SRC
+
+As print is of type =Show a => a -> (World -> ((), World))=, we know
+=res = ()= (=unit= type). If you didn't see what was magic here, let's
+try with three lines this time.
+
+#+BEGIN_SRC haskell :eval never-export
+ let (line1,w1) = getLine w0 in
+ let (line2,w2) = getLine w1 in
+ let ((),w3) = print (line1 ++ line2) in
+ ((),w3)
+#+END_SRC
+
+Which is equivalent to:
+
+#+BEGIN_SRC haskell :eval never-export
+ (res,w3) = (bind getLine (\line1 ->
+ (bind getLine (\line2 ->
+ print (line1 ++ line2))))) w0
+#+END_SRC
+
+Didn't you notice something? Yes, no temporary World variables are used
+anywhere! This is /MA/. /GIC/.
+
+We can use a better notation. Let's use =(>>=)= instead of =bind=.
+=(>>=)= is an infix function like =(+)=; reminder =3 + 4 ⇔ (+) 3 4=
+
+#+BEGIN_SRC haskell :eval never-export
+ (res,w3) = (getLine >>=
+ (\line1 -> getLine >>=
+ (\line2 -> print (line1 ++ line2)))) w0
+#+END_SRC
+
+fr; Haskell a confectionné du sucre syntaxique pour vous : Ho Ho Ho!
+Merry Christmas Everyone! Haskell has made syntactical sugar for us:
+
+#+BEGIN_SRC haskell :eval never-export
+ do
+ x <- action1
+ y <- action2
+ z <- action3
+ ...
+#+END_SRC
+
+Is replaced by:
+
+#+BEGIN_SRC haskell :eval never-export
+ action1 >>= (\x ->
+ action2 >>= (\y ->
+ action3 >>= (\z ->
+ ...
+ )))
+#+END_SRC
+
+Note that you can use =x= in =action2= and =x= and =y= in =action3=.
+
+But what about the lines not using the =<-=? Easy, another function
+=blindBind=:
+
+#+BEGIN_SRC haskell :eval never-export
+ blindBind :: IO a -> IO b -> IO b
+ blindBind action1 action2 w0 =
+ bind action (\_ -> action2) w0
+#+END_SRC
+
+I didn't simplify this definition for the purposes of clarity. Of
+course, we can use a better notation: we'll use the =(>>)= operator.
+
+And
+
+#+BEGIN_SRC haskell :eval never-export
+ do
+ action1
+ action2
+ action3
+#+END_SRC
+
+Is transformed into
+
+#+BEGIN_SRC haskell :eval never-export
+ action1 >>
+ action2 >>
+ action3
+#+END_SRC
+
+Also, another function is quite useful.
+
+#+BEGIN_SRC haskell :eval never-export
+ putInIO :: a -> IO a
+ putInIO x = IO (\w -> (x,w))
+#+END_SRC
+
+This is the general way to put pure values inside the "IO context". The
+general name for =putInIO= is =return=. This is quite a bad name when
+you learn Haskell. =return= is very different from what you might be
+used to.
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+03_Hell/01_IO/21_Detailled_IO.lhs
+
+To finish, let's translate our example:
+
+#+BEGIN_SRC haskell :eval never-export
+
+ askUser :: IO [Integer]
+ askUser = do
+ putStrLn "Enter a list of numbers (separated by commas):"
+ input <- getLine
+ let maybeList = getListFromString input in
+ case maybeList of
+ Just l -> return l
+ Nothing -> askUser
+
+ main :: IO ()
+ main = do
+ list <- askUser
+ print $ sum list
+#+END_SRC
+
+Is translated into:
+
+#+BEGIN_SRC haskell :eval never-export
+ import Data.Maybe
+
+ maybeRead :: Read a => String -> Maybe a
+ maybeRead s = case reads s of
+ [(x,"")] -> Just x
+ _ -> Nothing
+ getListFromString :: String -> Maybe [Integer]
+ getListFromString str = maybeRead $ "[" ++ str ++ "]"
+ askUser :: IO [Integer]
+ askUser =
+ putStrLn "Enter a list of numbers (sep. by commas):" >>
+ getLine >>= \input ->
+ let maybeList = getListFromString input in
+ case maybeList of
+ Just l -> return l
+ Nothing -> askUser
+
+ main :: IO ()
+ main = askUser >>=
+ \list -> print $ sum list
+#+END_SRC
+
+You can compile this code to verify that it works.
+
+Imagine what it would look like without the =(>>)= and =(>>=)=.
+
+03_Hell/01_IO/21_Detailled_IO.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+03_Hell/02_Monads/10_Monads.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Monads
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+blogimage("dali_reve.jpg","Dali, reve. It represents a weapon out of the
+mouth of a tiger, itself out of the mouth of another tiger, itself out
+of the mouth of a fish itself out of a grenade. I could have choosen a
+picture of the Human centipede as it is a very good representation of
+what a monad really is. But just to think about it, I find this
+disgusting and that wasn't the purpose of this document.")
+
+Now the secret can be revealed: =IO= is a /monad/. Being a monad means
+you have access to some syntactical sugar with the =do= notation. But
+mainly, you have access to a coding pattern which will ease the flow of
+your code.
+
+#+BEGIN_QUOTE
+ *Important remarks*:
+
+ - Monad are not necessarily about effects! There are a lot of /pure/
+ monads.
+ - Monad are more about sequencing
+#+END_QUOTE
+
+In Haskell, =Monad= is a type class. To be an instance of this type
+class, you must provide the functions =(>>=)= and =return=. The function
+=(>>)= is derived from =(>>=)=. Here is how the type class =Monad= is
+declared (basically):
+
+#+BEGIN_SRC haskell :eval never-export
+ class Monad m where
+ (>>=) :: m a -> (a -> m b) -> m b
+ return :: a -> m a
+
+ (>>) :: m a -> m b -> m b
+ f >> g = f >>= \_ -> g
+
+ -- You should generally safely ignore this function
+ -- which I believe exists for historical reasons
+ fail :: String -> m a
+ fail = error
+#+END_SRC
+
+#+BEGIN_QUOTE
+ Remarks:
+
+ - the keyword =class= is not your friend. A Haskell class is /not/ a
+ class of the kind you will find in object-oriented programming. A
+ Haskell class has a lot of similarities with Java interfaces. A
+ better word would have been =typeclass=, since that means a set of
+ types. For a type to belong to a class, all functions of the class
+ must be provided for this type.
+ - In this particular example of type class, the type =m= must be a
+ type that takes an argument. for example =IO a=, but also =Maybe a=,
+ =[a]=, etc...
+ - To be a useful monad, your function must obey some rules. If your
+ construction does not obey these rules strange things might happens:
+#+END_QUOTE
+
+#+BEGIN_QUOTE
+ #+BEGIN_EXAMPLE
+ return a >>= k == k a
+ m >>= return == m
+ m >>= (\x -> k x >>= h) == (m >>= k) >>= h
+ #+END_EXAMPLE
+#+END_QUOTE
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Maybe is a monad
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+There are a lot of different types that are instances of =Monad=. One of
+the easiest to describe is =Maybe=. If you have a sequence of =Maybe=
+values, you can use monads to manipulate them. It is particularly useful
+to remove very deep =if..then..else..= constructions.
+
+Imagine a complex bank operation. You are eligible to gain about 700€
+only if you can afford to follow a list of operations without your
+balance dipping below zero.
+
+#+BEGIN_SRC haskell :eval never-export
+ deposit value account = account + value
+ withdraw value account = account - value
+
+ eligible :: (Num a,Ord a) => a -> Bool
+ eligible account =
+ let account1 = deposit 100 account in
+ if (account1 < 0)
+ then False
+ else
+ let account2 = withdraw 200 account1 in
+ if (account2 < 0)
+ then False
+ else
+ let account3 = deposit 100 account2 in
+ if (account3 < 0)
+ then False
+ else
+ let account4 = withdraw 300 account3 in
+ if (account4 < 0)
+ then False
+ else
+ let account5 = deposit 1000 account4 in
+ if (account5 < 0)
+ then False
+ else
+ True
+
+ main = do
+ print $ eligible 300 -- True
+ print $ eligible 299 -- False
+#+END_SRC
+
+03_Hell/02_Monads/10_Monads.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+03_Hell/02_Monads/11_Monads.lhs
+
+Now, let's make it better using Maybe and the fact that it is a Monad
+
+#+BEGIN_SRC haskell :eval never-export
+ deposit :: (Num a) => a -> a -> Maybe a
+ deposit value account = Just (account + value)
+
+ withdraw :: (Num a,Ord a) => a -> a -> Maybe a
+ withdraw value account = if (account < value)
+ then Nothing
+ else Just (account - value)
+
+ eligible :: (Num a, Ord a) => a -> Maybe Bool
+ eligible account = do
+ account1 <- deposit 100 account
+ account2 <- withdraw 200 account1
+ account3 <- deposit 100 account2
+ account4 <- withdraw 300 account3
+ account5 <- deposit 1000 account4
+ Just True
+
+ main = do
+ print $ eligible 300 -- Just True
+ print $ eligible 299 -- Nothing
+#+END_SRC
+
+03_Hell/02_Monads/11_Monads.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+03_Hell/02_Monads/12_Monads.lhs
+
+Not bad, but we can make it even better:
+
+#+BEGIN_SRC haskell :eval never-export
+ deposit :: (Num a) => a -> a -> Maybe a
+ deposit value account = Just (account + value)
+
+ withdraw :: (Num a,Ord a) => a -> a -> Maybe a
+ withdraw value account = if (account < value)
+ then Nothing
+ else Just (account - value)
+
+ eligible :: (Num a, Ord a) => a -> Maybe Bool
+ eligible account =
+ deposit 100 account >>=
+ withdraw 200 >>=
+ deposit 100 >>=
+ withdraw 300 >>=
+ deposit 1000 >>
+ return True
+
+ main = do
+ print $ eligible 300 -- Just True
+ print $ eligible 299 -- Nothing
+#+END_SRC
+
+We have proven that Monads are a good way to make our code more elegant.
+Note this idea of code organization, in particular for =Maybe= can be
+used in most imperative languages. In fact, this is the kind of
+construction we make naturally.
+
+#+BEGIN_QUOTE
+ An important remark:
+
+ The first element in the sequence being evaluated to =Nothing= will
+ stop the complete evaluation. This means you don't execute all lines.
+ You get this for free, thanks to laziness.
+#+END_QUOTE
+
+You could also replay these example with the definition of =(>>=)= for
+=Maybe= in mind:
+
+#+BEGIN_SRC haskell :eval never-export
+ instance Monad Maybe where
+ (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
+ Nothing >>= _ = Nothing
+ (Just x) >>= f = f x
+
+ return x = Just x
+#+END_SRC
+
+The =Maybe= monad proved to be useful while being a very simple example.
+We saw the utility of the =IO= monad. But now for a cooler example,
+lists.
+
+03_Hell/02_Monads/12_Monads.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+03_Hell/02_Monads/13_Monads.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+The list monad
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+blogimage("golconde.jpg","Golconde de Magritte")
+
+The list monad helps us to simulate non-deterministic computations. Here
+we go:
+
+#+BEGIN_SRC haskell :eval never-export
+ import Control.Monad (guard)
+
+ allCases = [1..10]
+
+ resolve :: [(Int,Int,Int)]
+ resolve = do
+ x <- allCases
+ y <- allCases
+ z <- allCases
+ guard $ 4*x + 2*y < z
+ return (x,y,z)
+
+ main = do
+ print resolve
+#+END_SRC
+
+MA. GIC. :
+
+#+BEGIN_EXAMPLE
+ [(1,1,7),(1,1,8),(1,1,9),(1,1,10),(1,2,9),(1,2,10)]
+#+END_EXAMPLE
+
+For the list monad, there is also this syntactic sugar:
+
+#+BEGIN_SRC haskell :eval never-export
+ print $ [ (x,y,z) | x <- allCases,
+ y <- allCases,
+ z <- allCases,
+ 4*x + 2*y < z ]
+#+END_SRC
+
+I won't list all the monads, since there are many of them. Using monads
+simplifies the manipulation of several notions in pure languages. In
+particular, monads are very useful for:
+
+- IO,
+- non-deterministic computation,
+- generating pseudo random numbers,
+- keeping configuration state,
+- writing state,
+- ...
+
+If you have followed me until here, then you've done it! You know
+monads[fn:7]!
+
+03_Hell/02_Monads/13_Monads.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+Appendix
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+This section is not so much about learning Haskell. It is just here to
+discuss some details further.
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+04_Appendice/01_More_on_infinite_trees/10_Infinite_Trees.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+More on Infinite Tree
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+In the section [[#infinite-structures][Infinite Structures]] we saw some
+simple constructions. Unfortunately we removed two properties from our
+tree:
+
+1. no duplicate node value
+2. well ordered tree
+
+In this section we will try to keep the first property. Concerning the
+second one, we must relax it but we'll discuss how to keep it as much as
+possible.
+
+This code is mostly the same as the one in the [[#trees][tree section]].
+
+#+BEGIN_SRC haskell :eval never-export
+ import Data.List
+ data BinTree a = Empty
+ | Node a (BinTree a) (BinTree a)
+ deriving (Eq,Ord)
+
+ -- declare BinTree a to be an instance of Show
+ instance (Show a) => Show (BinTree a) where
+ -- will start by a '<' before the root
+ -- and put a : a begining of line
+ show t = "< " ++ replace '\n' "\n: " (treeshow "" t)
+ where
+ treeshow pref Empty = ""
+ treeshow pref (Node x Empty Empty) =
+ (pshow pref x)
+
+ treeshow pref (Node x left Empty) =
+ (pshow pref x) ++ "\n" ++
+ (showSon pref "`--" " " left)
+
+ treeshow pref (Node x Empty right) =
+ (pshow pref x) ++ "\n" ++
+ (showSon pref "`--" " " right)
+
+ treeshow pref (Node x left right) =
+ (pshow pref x) ++ "\n" ++
+ (showSon pref "|--" "| " left) ++ "\n" ++
+ (showSon pref "`--" " " right)
+
+ -- show a tree using some prefixes to make it nice
+ showSon pref before next t =
+ pref ++ before ++ treeshow (pref ++ next) t
+
+ -- pshow replace "\n" by "\n"++pref
+ pshow pref x = replace '\n' ("\n"++pref) (show x)
+
+ -- replace on char by another string
+ replace c new string =
+ concatMap (change c new) string
+ where
+ change c new x
+ | x == c = new
+ | otherwise = x:[] -- "x"
+#+END_SRC
+
+Our first step is to create some pseudo-random number list:
+
+#+BEGIN_SRC haskell :eval never-export
+ shuffle = map (\x -> (x*3123) `mod` 4331) [1..]
+#+END_SRC
+
+Just as a reminder, here is the definition of =treeFromList=
+
+#+BEGIN_SRC haskell :eval never-export
+ treeFromList :: (Ord a) => [a] -> BinTree a
+ treeFromList [] = Empty
+ treeFromList (x:xs) = Node x (treeFromList (filter (x) xs))
+#+END_SRC
+
+and =treeTakeDepth=:
+
+#+BEGIN_SRC haskell :eval never-export
+ treeTakeDepth _ Empty = Empty
+ treeTakeDepth 0 _ = Empty
+ treeTakeDepth n (Node x left right) = let
+ nl = treeTakeDepth (n-1) left
+ nr = treeTakeDepth (n-1) right
+ in
+ Node x nl nr
+#+END_SRC
+
+See the result of:
+
+#+BEGIN_SRC haskell :eval never-export
+ main = do
+ putStrLn "take 10 shuffle"
+ print $ take 10 shuffle
+ putStrLn "\ntreeTakeDepth 4 (treeFromList shuffle)"
+ print $ treeTakeDepth 4 (treeFromList shuffle)
+#+END_SRC
+
+#+BEGIN_EXAMPLE
+ % runghc 02_Hard_Part/41_Infinites_Structures.lhs
+ take 10 shuffle
+ [3123,1915,707,3830,2622,1414,206,3329,2121,913]
+ treeTakeDepth 4 (treeFromList shuffle)
+
+ < 3123
+ : |--1915
+ : | |--707
+ : | | |--206
+ : | | `--1414
+ : | `--2622
+ : | |--2121
+ : | `--2828
+ : `--3830
+ : |--3329
+ : | |--3240
+ : | `--3535
+ : `--4036
+ : |--3947
+ : `--4242
+#+END_EXAMPLE
+
+Yay! It ends! Beware though, it will only work if you always have
+something to put into a branch.
+
+For example
+
+#+BEGIN_SRC haskell :eval never-export
+ treeTakeDepth 4 (treeFromList [1..])
+#+END_SRC
+
+will loop forever. Simply because it will try to access the head of
+=filter (<1) [2..]=. But =filter= is not smart enought to understand
+that the result is the empty list.
+
+Nonetheless, it is still a very cool example of what non strict programs
+have to offer.
+
+Left as an exercise to the reader:
+
+- Prove the existence of a number =n= so that
+ =treeTakeDepth n (treeFromList shuffle)= will enter an infinite loop.
+- Find an upper bound for =n=.
+- Prove there is no =shuffle= list so that, for any depth, the program
+ ends.
+
+04_Appendice/01_More_on_infinite_trees/10_Infinite_Trees.lhs
+
+#+BEGIN_HTML
+
+#+END_HTML
+
+04_Appendice/01_More_on_infinite_trees/11_Infinite_Trees.lhs
+
+This code is mostly the same as the preceding one.
+
+#+BEGIN_SRC haskell :eval never-export
+ import Debug.Trace (trace)
+ import Data.List
+ data BinTree a = Empty
+ | Node a (BinTree a) (BinTree a)
+ deriving (Eq,Ord)
+#+END_SRC
+
+#+BEGIN_SRC haskell :eval never-export
+ -- declare BinTree a to be an instance of Show
+ instance (Show a) => Show (BinTree a) where
+ -- will start by a '<' before the root
+ -- and put a : a begining of line
+ show t = "< " ++ replace '\n' "\n: " (treeshow "" t)
+ where
+ treeshow pref Empty = ""
+ treeshow pref (Node x Empty Empty) =
+ (pshow pref x)
+
+ treeshow pref (Node x left Empty) =
+ (pshow pref x) ++ "\n" ++
+ (showSon pref "`--" " " left)
+
+ treeshow pref (Node x Empty right) =
+ (pshow pref x) ++ "\n" ++
+ (showSon pref "`--" " " right)
+
+ treeshow pref (Node x left right) =
+ (pshow pref x) ++ "\n" ++
+ (showSon pref "|--" "| " left) ++ "\n" ++
+ (showSon pref "`--" " " right)
+
+ -- show a tree using some prefixes to make it nice
+ showSon pref before next t =
+ pref ++ before ++ treeshow (pref ++ next) t
+
+ -- pshow replace "\n" by "\n"++pref
+ pshow pref x = replace '\n' ("\n"++pref) (" " ++ show x)
+
+ -- replace on char by another string
+ replace c new string =
+ concatMap (change c new) string
+ where
+ change c new x
+ | x == c = new
+ | otherwise = x:[] -- "x"
+
+ treeTakeDepth _ Empty = Empty
+ treeTakeDepth 0 _ = Empty
+ treeTakeDepth n (Node x left right) = let
+ nl = treeTakeDepth (n-1) left
+ nr = treeTakeDepth (n-1) right
+ in
+ Node x nl nr
+#+END_SRC
+
+In order to resolve these problem we will modify slightly our
+=treeFromList= and =shuffle= function.
+
+A first problem, is the lack of infinite different number in our
+implementation of =shuffle=. We generated only =4331= different numbers.
+To resolve this we make a slightly better =shuffle= function.
+
+#+BEGIN_SRC haskell :eval never-export
+ shuffle = map rand [1..]
+ where
+ rand x = ((p x) `mod` (x+c)) - ((x+c) `div` 2)
+ p x = m*x^2 + n*x + o -- some polynome
+ m = 3123
+ n = 31
+ o = 7641
+ c = 1237
+#+END_SRC
+
+This shuffle function has the property (hopefully) not to have an upper
+nor lower bound. But having a better shuffle list isn't enough not to
+enter an infinite loop.
+
+Generally, we cannot decide whether =filter ( [a] -> BinTree a
+ treeFromList [] = Empty
+ treeFromList (x:xs) = Node x left right
+ where
+ left = treeFromList $ safefilter (x) xs
+#+END_SRC
+
+This new function =safefilter= is almost equivalent to =filter= but
+don't enter infinite loop if the result is a finite list. If it cannot
+find an element for which the test is true after 10000 consecutive
+steps, then it considers to be the end of the search.
+
+#+BEGIN_SRC haskell :eval never-export
+ safefilter :: (a -> Bool) -> [a] -> [a]
+ safefilter f l = safefilter' f l nbTry
+ where
+ nbTry = 10000
+ safefilter' _ _ 0 = []
+ safefilter' _ [] _ = []
+ safefilter' f (x:xs) n =
+ if f x
+ then x : safefilter' f xs nbTry
+ else safefilter' f xs (n-1)
+#+END_SRC
+
+Now run the program and be happy:
+
+#+BEGIN_SRC haskell :eval never-export
+ main = do
+ putStrLn "take 10 shuffle"
+ print $ take 10 shuffle
+ putStrLn "\ntreeTakeDepth 8 (treeFromList shuffle)"
+ print $ treeTakeDepth 8 (treeFromList $ shuffle)
+#+END_SRC
+
+You should realize the time to print each value is different. This is
+because Haskell compute each value when it needs it. And in this case,
+this is when asked to print it on the screen.
+
+Impressively enough, try to replace the depth from =8= to =100=. It will
+work without killing your RAM! The flow and the memory management is
+done naturally by Haskell.
+
+Left as an exercise to the reader:
+
+- Even with large constant value for =deep= and =nbTry=, it seems to
+ work nicely. But in the worst case, it can be exponential. Create a
+ worst case list to give as parameter to =treeFromList=.\\
+ /hint/: think about (=[0,-1,-1,....,-1,1,-1,...,-1,1,...]=).
+- I first tried to implement =safefilter= as follow:
+
+ #+BEGIN_HTML
+
+ safefilter' f l = if filter f (take 10000 l) == []
+ then []
+ else filter f l
+
+ #+END_HTML
+
+ Explain why it doesn't work and can enter into an infinite loop.
+- Suppose that =shuffle= is real random list with growing bounds. If you
+ study a bit this structure, you'll discover that with probability 1,
+ this structure is finite. Using the following code (suppose we could
+ use =safefilter'= directly as if was not in the where of safefilter)
+ find a definition of =f= such that with probability =1=,
+ =treeFromList' shuffle= is infinite. And prove it. Disclaimer, this is
+ only a conjecture.
+
+#+BEGIN_SRC haskell :eval never-export
+ treeFromList' [] n = Empty
+ treeFromList' (x:xs) n = Node x left right
+ where
+ left = treeFromList' (safefilter' (x) xs (f n)
+ f = ???
+#+END_SRC
+
+04_Appendice/01_More_on_infinite_trees/11_Infinite_Trees.lhs
+
+** Thanks
+ :PROPERTIES:
+ :CUSTOM_ID: thanks
+ :END:
+
+Thanks to [[http://reddit.com/r/haskell][=/r/haskell=]] and
+[[http://reddit.com/r/programming][=/r/programming=]]. Your comment were
+most than welcome.
+
+Particularly, I want to thank [[https://github.com/Emm][Emm]] a thousand
+times for the time he spent on correcting my English. Thank you man.
+
+[fn:1] Even if most recent languages try to hide them, they are present.
+
+[fn:2] I know I'm cheating. But I will talk about non-strictness later.
+
+[fn:3] For the brave, a more complete explanation of pattern matching
+ can be found
+ [[http://www.cs.auckland.ac.nz/references/haskell/haskell-intro-html/patterns.html][here]].
+
+[fn:4] Which is itself very similar to the javascript =eval= function,
+ that is applied to a string containing JSON.
+
+[fn:5] There are some /unsafe/ exceptions to this rule. But you
+ shouldn't see such use in a real application except maybe for
+ debugging purposes.
+
+[fn:6] For the curious ones, the real type is
+ =data IO a = IO {unIO :: State# RealWorld -> (# State# RealWorld, a #)}=.
+ All the =#= has to do with optimisation and I swapped the fields
+ in my example. But this is the basic idea.
+
+[fn:7] Well, you'll certainly need to practice a bit to get used to them
+ and to understand when you can use them and create your own. But
+ you already made a big step in this direction.
diff --git a/src/drafts/blog-detoxify-web.org b/src/drafts/blog-detoxify-web.org
new file mode 100644
index 0000000..c8413ac
--- /dev/null
+++ b/src/drafts/blog-detoxify-web.org
@@ -0,0 +1,39 @@
+#+TITLE: Detoxify the Web
+#+SUBTITLE: Take back control of what we are exposed to on the web
+#+AUTHOR: Yann Esposito
+
+We are currently in an age were where you take your eyeball is a valuable resource.
+As such there are professional, and a lot of smart ones, whose only job is to ensure
+you pass more time looking at what there is best in their interrest, not yours.
+
+There are a lot of techniques to grab your attention and not letting it go somewhere else.
+
+- animation
+- colors
+- gaming the relationship
+- entertaining
+
+All of them are in fact not really problematic. But now, this is too much.
+So in order to feel calm again we need to have better control of what we see, are exposed to.
+
+If you take a look into the gopher sphere, you discover a lot text-oriented world.
+Of course there are pictures, but not in the middle of the article.
+
+So mostly text. No gif, no animation, no music, no video, just textual content.
+
+We passed from a world where there was too much textual content, to a world filled
+with meaningless animations, colors, pictures, effects, popups, etc...
+
+*Detoxify the web*
+
+Here is my solution:
+
+- remove all the styles of all the websites so a lot of website cannot be used anymore that way.
+- replace by a default focus oriented style.
+
+My only solution is to start a proxy between me and the web, I take the content and do a lot of cleanup.
+I remove all the CSS (faster), I use my own (nicer and contolled)
+
+Simple and efficient.
+
+This transformation should be done by the client.
diff --git a/src/drafts/sad-text-browsing.org b/src/drafts/sad-text-browsing.org
new file mode 100644
index 0000000..aa6fd6c
--- /dev/null
+++ b/src/drafts/sad-text-browsing.org
@@ -0,0 +1,13 @@
+#+TITLE: The sad state of text browsing
+#+AUTHOR: Yann Esposito
+
+1. sad state, show HN, Reddit, worse, news websites, etc...
+2. bad for disabled people
+3. why not change the concept and make the provider of content not also provide the Look & Feel
+ User controlled display of content. Less money, more quality, is it possible
+ - no js
+ - text only
+ - interaction? controlled one
+ - user facing code, yes, only signature, all the rest looks like bullshit to me
+4. not web 3.0, more like, fuck it, we need a BRUTALIST, Hacker-only oriented
+ web. A safe place to talk between civilised people. What are the possible solutions
diff --git a/src/index.org b/src/index.org
index 637c764..e0c267f 100644
--- a/src/index.org
+++ b/src/index.org
@@ -8,21 +8,8 @@
#+OPTIONS: H:5
#+STARTUP: showeverything
-This is a new take on my personal blog.
-I tried to have some minimalism in mind but not too much.
+Welcome to my personal blog.
+This is the 4th time I change the underlying technology behind my blog.
-True minimalism would have been to only serve text files.
-But I would prefer to have at least links working. Also
-syntax highlighting of source code is nice.
-
-But I dislike the new trend of design space and white colors.
-It doesn't really fit the spirit of my website.
-So it looks a bit more like a text into a colored terminal.
-
-The CSS support dark/light theme.
-If unknown, the default color scheme is dark in the hope to save a bit of energy
-from screen.
-You can have a basic demo about most supported content styles/type (paragraphs,
-lists, tables, etc...) [[file:./demo.org][here]].
-
-I write all the content with [[http://orgmode.org][org-mode]].
+- [[./archive.html][posts]]
+- [[./about][about me]]
diff --git a/src/posts/2019-07-04-static-org-publish.org b/src/posts/2019-07-04-static-org-publish.org
index e815e53..c2ccc8f 100644
--- a/src/posts/2019-07-04-static-org-publish.org
+++ b/src/posts/2019-07-04-static-org-publish.org
@@ -1,15 +1,15 @@
#+TITLE: Static blog with org-mode
#+AUTHOR: Yann Esposito
#+EMAIL: yann.esposito@gmail.com
-#+DATE: 2019-07-04
+#+DATE: 2019-07-27
#+KEYWORDS: programming, blog, org-mode
#+OPTIONS: auto-id:t
#+begin_quote
-/tl;dr/: [[#current-solution-0a92][Full code for the impatient↓]]. Read the full blog post to have all the details.
+/tl;dr/: [[#current-solution][Full code for the impatient↓]].
+Read the full blog post to have all the details.
#+end_quote
-
This is the first article using my new blog system.
Once in a while, I create a new personal website.
@@ -63,6 +63,11 @@ You can add a task quite easily while doing other work in emacs.
:CUSTOM_ID: how--831e
:END:
+You can easily follow the org-mode doc to make your own website.
+But I have added a few "goodies".
+
+- attempt to obfuscate contact email,
+
** Basic Blog
:PROPERTIES:
:CUSTOM_ID: basic-blog-a1fc
@@ -70,8 +75,7 @@ You can add a task quite easily while doing other work in emacs.
I put the need minimal code in a =.project.el.gpg= file of my blog repository.
Inspired by this [[https://francismurillo.github.io/2017-02-15-Project-Script-Loader/][blog post]] I enhanced this version to be both more user friendly
-and secure (see [[#digression]]).
-
+and secure (see [[./autoload-emacs-script-by-project.org][Autoload Emacs Script by Project]]).
But even before that, I simply put the code in has an elisp code block of my
=index.org= that I exectued with =C-c C-c=.
@@ -188,7 +192,7 @@ That's better. But for a blog you also generally want to have your own CSS.
* Current Solution
:PROPERTIES:
- :CUSTOM_ID: current-solution-0a92
+ :CUSTOM_ID: current-solution
:END:
#+begin_src elisp
@@ -201,7 +205,8 @@ That's better. But for a blog you also generally want to have your own CSS.
(setq rss-dir base-dir)
(setq publish-rss-dir publish-dir)
(setq css-name "minimalist.css")
-
+ (setq author-name "Yann Esposito")
+ (setq author-email "yann.esposito@gmail.com")
(require 'org)
(require 'ox-publish)
@@ -211,8 +216,8 @@ That's better. But for a blog you also generally want to have your own CSS.
(defun org-blog-prepare (project-plist)
"With help from `https://github.com/howardabrams/dot-files'.
- Touch `index.org' to rebuilt it.
- Argument `PROJECT-PLIST' contains information about the current project."
+ Touch `index.org' to rebuilt it.
+ Argument `PROJECT-PLIST' contains information about the current project."
(let* ((base-directory (plist-get project-plist :base-directory))
(buffer (find-file-noselect (expand-file-name "index.org" base-directory) t)))
(with-current-buffer buffer
@@ -224,7 +229,7 @@ That's better. But for a blog you also generally want to have your own CSS.
""
""
""
- ""))
+ ""))
(defun menu (lst)
"Blog menu"
@@ -320,8 +325,8 @@ That's better. But for a blog you also generally want to have your own CSS.
(defun org-blog-sitemap-function (title list)
"Return sitemap using TITLE and LIST returned by `org-blog-sitemap-format-entry'."
(concat "#+TITLE: " title "\n"
- "#+AUTHOR: Yann Esposito\n"
- "#+EMAIL: yann.esposito@gmail.com\n"
+ "#+AUTHOR: " author-name "\n"
+ "#+EMAIL: " author-email "\n"
"\n#+begin_archive\n"
(mapconcat (lambda (li)
(format "@@html: