Added images, fixed syntax highlighting
|
@ -233,14 +233,14 @@ figure, .figure {
|
|||
--b1: #989EA8;
|
||||
--b2: #E5E8ED;
|
||||
--b3: #F4F7FC;
|
||||
--y: #A98D50;
|
||||
--o: #aa6550;
|
||||
--r: #b85a64;
|
||||
--y: #A98D50;
|
||||
--o: #aa6550;
|
||||
--r: #b85a64;
|
||||
--m: #af53b0;
|
||||
--violet: #846f93;
|
||||
--b: #5679a4;
|
||||
--cyan: #4c8493;
|
||||
--g: #728b5c;
|
||||
--v: #846f93;
|
||||
--b: #5679a4;
|
||||
--c: #4c8493;
|
||||
--g: #728b5c;
|
||||
|
||||
/* Solaryzed accented colors */
|
||||
--bg: var(--b03);
|
||||
|
@ -438,7 +438,7 @@ blockquote:after, .main blockquote:after {
|
|||
}
|
||||
|
||||
.org-rainbow-delimiters-depth-2, .org-nix-builtin, .org-variable-name,
|
||||
.org-function-name, .org-diff-changed {
|
||||
.org-haskell-definition, .org-haskell-operator, .org-function-name, .org-diff-changed {
|
||||
color:var(--b);
|
||||
}
|
||||
|
||||
|
@ -453,11 +453,11 @@ blockquote:after, .main blockquote:after {
|
|||
.org-rainbow-delimiters-depth-5, .org-diff-removed, .TODO {
|
||||
color:var(--r);
|
||||
}
|
||||
.org-rainbow-delimiters-depth-6 {
|
||||
.org-rainbow-delimiters-depth-6, .org-haskell-constructor {
|
||||
color:var(--o);
|
||||
}
|
||||
.org-rainbow-delimiters-depth-7, .org-type, .org-constant, .org-diff-header,
|
||||
.IN_PROGRESS {
|
||||
.org-haskell-keyword, .org-haskell-type, .IN_PROGRESS {
|
||||
color:var(--y);
|
||||
}
|
||||
.org-rainbow-delimiters-depth-8, .org-sh-heredoc, .org-diff-added, .org-string,
|
||||
|
@ -472,6 +472,7 @@ blockquote:after, .main blockquote:after {
|
|||
color:var(--fg2);
|
||||
}
|
||||
|
||||
.org-highlight-number-number {
|
||||
.org-highlight-numbers-number, .org-highlight-number-number
|
||||
{
|
||||
color:var(--rfg);
|
||||
}
|
||||
|
|
BIN
src/posts/0010-Haskell-Now/Haskell-logo.png
Normal file
After Width: | Height: | Size: 5.2 KiB |
BIN
src/posts/0010-Haskell-Now/dali_reve.jpg
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
src/posts/0010-Haskell-Now/dangerous_book.png
Normal file
After Width: | Height: | Size: 18 KiB |
BIN
src/posts/0010-Haskell-Now/escher_infinite_lizards.jpg
Normal file
After Width: | Height: | Size: 134 KiB |
BIN
src/posts/0010-Haskell-Now/escher_polygon.png
Normal file
After Width: | Height: | Size: 36 KiB |
BIN
src/posts/0010-Haskell-Now/golconde.jpg
Normal file
After Width: | Height: | Size: 98 KiB |
After Width: | Height: | Size: 53 KiB |
|
@ -1,33 +1,29 @@
|
|||
#+title: Learn Haskell Fast and Hard
|
||||
#+subtitle: Blow your mind with Haskell
|
||||
#+date: [2012-02-08]
|
||||
#+date: [2019-12-15 Sun]
|
||||
#+author: Yann Esposito
|
||||
#+EMAIL: yann@esposito.host
|
||||
#+keywords: Haskell, programming, functional, tutorial |
|
||||
#+DESCRIPTION: Meta article about how I generate this blog.
|
||||
#+DESCRIPTION: Haskell programming tutorial update
|
||||
#+OPTIONS: auto-id:t toc:t
|
||||
|
||||
#+begin_notes
|
||||
A very short and dense tutorial for learning Haskell.
|
||||
A very short and intense introduction to Haskell.
|
||||
|
||||
This is an update of my old (2012) article.
|
||||
A lot of things have changed since then.
|
||||
And I took the time to read it again.
|
||||
#+end_notes
|
||||
|
||||
Thanks to:
|
||||
#+begin_quote
|
||||
*Prelude*
|
||||
|
||||
- [[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.
|
||||
In 2012, I really believed that every developer should learn Haskell.
|
||||
It is the end of 2019 and I still believe it.
|
||||
I don't think everyone needs to be a super Haskell ninja, but they should
|
||||
at least discover what Haskell has to offer.
|
||||
Learning Haskell opens your mind.
|
||||
#+end_quote
|
||||
|
||||
Mainstream languages share the same foundations:
|
||||
|
||||
|
@ -36,27 +32,32 @@ Mainstream languages share the same foundations:
|
|||
- 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.
|
||||
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.
|
||||
But learning Haskell can be hard.
|
||||
It was for me.
|
||||
In this article I try to provide as much help as possible to accelerate
|
||||
your 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.
|
||||
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 and rewarding.
|
||||
|
||||
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.
|
||||
Today, I could not really provide a conventional path to learn Haskell.
|
||||
So I think the best I can do is point you to the [[https://www.haskell.org/documentation/][haskell.org]] documentation
|
||||
website.
|
||||
And you will see that most path involve a quite long learning process.
|
||||
By that, I mean that you should read a long book and invest a lot of hours
|
||||
and certainly days before having a good idea about what Haskell is all about.
|
||||
|
||||
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.
|
||||
major aspects of Haskell.
|
||||
I also added some information I lacked while I learned Haskell.
|
||||
|
||||
The article contains five parts:
|
||||
|
||||
|
@ -80,20 +81,6 @@ The article contains five parts:
|
|||
- 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
|
||||
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
|
||||
|
@ -104,7 +91,8 @@ The article contains five parts:
|
|||
:CUSTOM_ID: install
|
||||
:END:
|
||||
|
||||
blogimage("Haskell-logo.png", "Haskell logo")
|
||||
#+CAPTION: Haskell logo
|
||||
[[./Haskell-logo.png]]
|
||||
|
||||
There are different way to install Haskell, I would recommend to use
|
||||
[[https://haskellstack.org][=stack=]].
|
||||
|
@ -124,7 +112,8 @@ Tools:
|
|||
:CUSTOM_ID: don't-be-afraid
|
||||
:END:
|
||||
|
||||
blogimage("munch_TheScream.jpg","The Scream")
|
||||
#+CAPTION: The Scream
|
||||
[[./munch_TheScream.jpg]]
|
||||
|
||||
Many books/articles about Haskell start by introducing some esoteric
|
||||
formula (quick sort, Fibonacci, etc...). I will do the exact opposite.
|
||||
|
@ -217,7 +206,8 @@ languages.
|
|||
:CUSTOM_ID: very-basic-haskell
|
||||
:END:
|
||||
|
||||
blogimage("picasso_owl.jpg","Picasso minimal owl")
|
||||
#+CAPTION: Picasso minimal owl
|
||||
[[./picasso_owl.jpg]]
|
||||
|
||||
Before continuing you need to be warned about some essential properties
|
||||
of Haskell.
|
||||
|
@ -521,7 +511,8 @@ really watch this great (and funny) video:
|
|||
:CUSTOM_ID: essential-haskell
|
||||
:END:
|
||||
|
||||
blogimage("kandinsky_gugg.jpg","Kandinsky Gugg")
|
||||
#+CAPTION: Kandinsky Gugg
|
||||
[[./kandinsky_gugg.jpg]]
|
||||
|
||||
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
|
||||
|
@ -769,7 +760,8 @@ The hard part can now begin.
|
|||
:CUSTOM_ID: functional-style
|
||||
:END:
|
||||
|
||||
blogimage("hr_giger_biomechanicallandscape_500.jpg","Biomechanical Landscape by H.R. Giger")
|
||||
#+CAPTION: Biomechanical Landscape by H.R. Giger
|
||||
[[./hr_giger_biomechanicallandscape_500.jpg]]
|
||||
|
||||
In this section, I will give a short example of the impressive
|
||||
refactoring ability provided by Haskell. We will select a problem and
|
||||
|
@ -1056,7 +1048,8 @@ We use this method to remove the =l=:
|
|||
:CUSTOM_ID: higher-order-functions
|
||||
:END:
|
||||
|
||||
blogimage("escher_polygon.png","Escher")
|
||||
#+CAPTION: Escher
|
||||
[[./escher_polygon.png]]
|
||||
|
||||
To make things even better we should use higher order functions. What
|
||||
are these beasts? Higher order functions are functions taking functions
|
||||
|
@ -1286,7 +1279,8 @@ another essential aspect of Haskell: /Types/.
|
|||
:CUSTOM_ID: types
|
||||
:END:
|
||||
|
||||
blogimage("salvador-dali-the-madonna-of-port-lligat.jpg","Dali, the madonna of port Lligat")
|
||||
#+CAPTION: Dali, the madonna of port Lligat
|
||||
[[./salvador-dali-the-madonna-of-port-lligat.jpg]]
|
||||
|
||||
#+BEGIN_QUOTE
|
||||
%tldr
|
||||
|
@ -1405,6 +1399,9 @@ errors are caught before run time. Generally, in Haskell:
|
|||
-----
|
||||
|
||||
*** Type construction
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: type-construction
|
||||
:END:
|
||||
|
||||
You can construct your own types. First, you can use aliases or type
|
||||
synonyms.
|
||||
|
@ -1565,7 +1562,8 @@ This prints:
|
|||
:CUSTOM_ID: trees
|
||||
:END:
|
||||
|
||||
blogimage("magritte-l-arbre.jpg","Magritte, l'Arbre")
|
||||
#+CAPTION: Magritte, l'Arbre
|
||||
[[./magritte-l-arbre.jpg]]
|
||||
|
||||
We'll just give another standard example: binary trees.
|
||||
|
||||
|
@ -1761,7 +1759,8 @@ Binary tree of Char binary trees:
|
|||
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")
|
||||
#+CAPTION: Yo Dawg Tree
|
||||
[[./yo_dawg_tree.jpg]]
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
putStrLn "\nTree of Binary trees of Char binary trees:"
|
||||
|
@ -1826,7 +1825,8 @@ a tree containing a tree of trees!
|
|||
:CUSTOM_ID: infinite-structures
|
||||
:END:
|
||||
|
||||
blogimage("escher_infinite_lizards.jpg","Escher")
|
||||
#+CAPTION: Escher
|
||||
[[./escher_infinite_lizards.jpg]]
|
||||
|
||||
It is often said that Haskell is /lazy/.
|
||||
|
||||
|
@ -2064,7 +2064,8 @@ rewarding.
|
|||
:CUSTOM_ID: deal-with-io
|
||||
:END:
|
||||
|
||||
blogimage("magritte_carte_blanche.jpg","Magritte, Carte blanche")
|
||||
#+CAPTION: Magritte, Carte blanche
|
||||
[[./magritte_carte_blanche.jpg]]
|
||||
|
||||
#+BEGIN_QUOTE
|
||||
%tldr
|
||||
|
@ -2331,7 +2332,8 @@ If you practice a bit, you should be able to /use/ =IO=.
|
|||
:CUSTOM_ID: io-trick-explained
|
||||
:END:
|
||||
|
||||
blogimage("magritte_pipe.jpg","Magritte, ceci n'est pas une pipe")
|
||||
#+CAPTION: Magritte, ceci n'est pas une pipe
|
||||
[[./magritte_pipe.jpg]]
|
||||
|
||||
#+BEGIN_QUOTE
|
||||
Here is a %tldr for this section.
|
||||
|
@ -2553,20 +2555,21 @@ 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
|
||||
#+BEGIN_SRC haskell
|
||||
let (x,w1) = action1 w0 in
|
||||
let (y,w2) = action2 x w1 in
|
||||
#+END_SRC
|
||||
|
||||
and
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
let (_,w1) = action1 w0 in
|
||||
let (y,w2) = action2 w1 in
|
||||
#+END_EXAMPLE
|
||||
#+BEGIN_SRC haskell
|
||||
let (_,w1) = action1 w0 in
|
||||
let (y,w2) = action2 w1 in
|
||||
#+END_SRC
|
||||
#+END_QUOTE
|
||||
|
||||
leftblogimage("jocker_pencil_trick.jpg","Jocker pencil trick")
|
||||
#+CAPTION: Jocker pencil trick
|
||||
[[./jocker_pencil_trick.jpg]]
|
||||
|
||||
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=
|
||||
|
@ -2805,12 +2808,13 @@ Imagine what it would look like without the =(>>)= and =(>>=)=.
|
|||
:END:
|
||||
|
||||
#+begin_comment
|
||||
blogimage("dali_reve.jpg","Dali, reve. It represents a weapon out of the
|
||||
#+CAPTION: 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.")
|
||||
disgusting and that wasn't the purpose of this document.
|
||||
[[./dali_reve.jpg]]
|
||||
#+end_comment
|
||||
|
||||
Now the secret can be revealed: =IO= is a /monad/. Being a monad means
|
||||
|
@ -3002,7 +3006,8 @@ lists.
|
|||
:CUSTOM_ID: the-list-monad
|
||||
:END:
|
||||
|
||||
blogimage("golconde.jpg","Golconde de Magritte")
|
||||
#+CAPTION: Golconde de Magritte
|
||||
[[./golconde.jpg]]
|
||||
|
||||
The list monad helps us to simulate non-deterministic computations. Here
|
||||
we go:
|
BIN
src/posts/0010-Haskell-Now/jocker_pencil_trick.jpg
Normal file
After Width: | Height: | Size: 17 KiB |
BIN
src/posts/0010-Haskell-Now/kandinsky_gugg.jpg
Normal file
After Width: | Height: | Size: 53 KiB |
BIN
src/posts/0010-Haskell-Now/learn_haskell_mordor.jpg
Normal file
After Width: | Height: | Size: 156 B |
BIN
src/posts/0010-Haskell-Now/magritte-l-arbre.jpg
Normal file
After Width: | Height: | Size: 15 KiB |
BIN
src/posts/0010-Haskell-Now/magritte_carte_blanche.jpg
Normal file
After Width: | Height: | Size: 34 KiB |
BIN
src/posts/0010-Haskell-Now/magritte_pipe.jpg
Normal file
After Width: | Height: | Size: 9.2 KiB |
BIN
src/posts/0010-Haskell-Now/magritte_pleasure_principle.jpg
Normal file
After Width: | Height: | Size: 19 KiB |
BIN
src/posts/0010-Haskell-Now/munch_TheScream.jpg
Normal file
After Width: | Height: | Size: 81 KiB |
BIN
src/posts/0010-Haskell-Now/picasso_owl.jpg
Normal file
After Width: | Height: | Size: 7.6 KiB |
After Width: | Height: | Size: 60 KiB |
BIN
src/posts/0010-Haskell-Now/yo_dawg_tree.jpg
Normal file
After Width: | Height: | Size: 68 KiB |