wip
This commit is contained in:
parent
383b69bc75
commit
7784f02483
|
@ -213,12 +213,6 @@ figure, .figure {
|
|||
.notes {
|
||||
padding: 5px 10px;
|
||||
}
|
||||
.notes::before {
|
||||
content: "☞";
|
||||
float: left;
|
||||
display: inline-block;
|
||||
width: 1.5em;
|
||||
}
|
||||
.underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
@ -376,12 +370,21 @@ pre::after,pre::before,hr:after,
|
|||
nav a, nav a:visited, .main nav a,.main nav a:visited {
|
||||
color: var(--fg2);
|
||||
}
|
||||
#labels label:hover, a:hover, a:active, a:focus, .main a:hover,.main a:active,.main a:focus,
|
||||
nav a:focus, nav a:hover, .main nav a:focus,.main nav a:hover {
|
||||
#labels label:hover,
|
||||
a:hover,
|
||||
a:hover *,
|
||||
.main a:hover,
|
||||
.main a:hover *,
|
||||
nav a:hover,
|
||||
.main nav a:hover {
|
||||
color: var(--l-fg);
|
||||
background: var(--l-bg);
|
||||
}
|
||||
|
||||
abbr { border-bottom: dashed 1px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
thead, .main thead, tr:hover, .main tr:hover {
|
||||
background: var(--rbg);
|
||||
color: var(--rfg);
|
||||
|
@ -428,6 +431,7 @@ blockquote:after, .main blockquote:after {
|
|||
.notes, .main .notes {
|
||||
background: var(--rbg);
|
||||
color: var(--rfg);
|
||||
margin: 1em 0;
|
||||
}
|
||||
/* ---- SYNTAX HIGHLIGHTING ---- */
|
||||
.org-rainbow-delimiters-depth-1, .org-rainbow-delimiters-depth-9,
|
||||
|
|
10
src/posts/0010-Haskell-Now/evenSum_v1.hs
Normal file
10
src/posts/0010-Haskell-Now/evenSum_v1.hs
Normal file
|
@ -0,0 +1,10 @@
|
|||
-- 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
|
6
src/posts/0010-Haskell-Now/evenSum_v10.hs
Normal file
6
src/posts/0010-Haskell-Now/evenSum_v10.hs
Normal file
|
@ -0,0 +1,6 @@
|
|||
-- Version 10
|
||||
import Data.List (foldl')
|
||||
sum' :: (Num a) => [a] -> a
|
||||
sum' = foldl' (+) 0
|
||||
evenSum :: Integral a => [a] -> a
|
||||
evenSum = sum' . (filter even)
|
11
src/posts/0010-Haskell-Now/evenSum_v2.hs
Normal file
11
src/posts/0010-Haskell-Now/evenSum_v2.hs
Normal file
|
@ -0,0 +1,11 @@
|
|||
-- 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
|
8
src/posts/0010-Haskell-Now/evenSum_v3.hs
Normal file
8
src/posts/0010-Haskell-Now/evenSum_v3.hs
Normal file
|
@ -0,0 +1,8 @@
|
|||
-- 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
|
9
src/posts/0010-Haskell-Now/evenSum_v4.hs
Normal file
9
src/posts/0010-Haskell-Now/evenSum_v4.hs
Normal file
|
@ -0,0 +1,9 @@
|
|||
-- 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
|
5
src/posts/0010-Haskell-Now/evenSum_v5.hs
Normal file
5
src/posts/0010-Haskell-Now/evenSum_v5.hs
Normal file
|
@ -0,0 +1,5 @@
|
|||
-- Version 5
|
||||
evenSum l = mysum 0 (filter even l)
|
||||
where
|
||||
mysum n [] = n
|
||||
mysum n (x:xs) = mysum (n+x) xs
|
6
src/posts/0010-Haskell-Now/evenSum_v6.hs
Normal file
6
src/posts/0010-Haskell-Now/evenSum_v6.hs
Normal file
|
@ -0,0 +1,6 @@
|
|||
-- 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
|
5
src/posts/0010-Haskell-Now/evenSum_v7.hs
Normal file
5
src/posts/0010-Haskell-Now/evenSum_v7.hs
Normal file
|
@ -0,0 +1,5 @@
|
|||
-- 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)
|
4
src/posts/0010-Haskell-Now/evenSum_v8.hs
Normal file
4
src/posts/0010-Haskell-Now/evenSum_v8.hs
Normal file
|
@ -0,0 +1,4 @@
|
|||
-- Version 8
|
||||
import Data.List (foldl')
|
||||
evenSum :: Integral a => [a] -> a
|
||||
evenSum l = foldl' (+) 0 (filter even l)
|
4
src/posts/0010-Haskell-Now/evenSum_v9.hs
Normal file
4
src/posts/0010-Haskell-Now/evenSum_v9.hs
Normal file
|
@ -0,0 +1,4 @@
|
|||
-- Version 9
|
||||
import Data.List (foldl')
|
||||
evenSum :: Integral a => [a] -> a
|
||||
evenSum = (foldl' (+) 0) . (filter even)
|
25
src/posts/0010-Haskell-Now/functions.hs
Normal file
25
src/posts/0010-Haskell-Now/functions.hs
Normal file
|
@ -0,0 +1,25 @@
|
|||
square :: Num a => a -> a
|
||||
square x = x^2
|
||||
|
||||
square' x = (^) x 2
|
||||
|
||||
square'' x = (^2) x
|
||||
|
||||
square''' = (^2)
|
||||
|
||||
absolute :: (Ord a, Num a) => a -> a
|
||||
absolute x = if x >= 0 then x else -x
|
||||
|
||||
absolute' x
|
||||
| x >= 0 = x
|
||||
| otherwise = -x
|
||||
|
||||
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)
|
|
@ -161,7 +161,7 @@ The article contains five parts:
|
|||
|
||||
- More on infinite tree; a more math oriented discussion about
|
||||
infinite trees
|
||||
** Helpers :noexport:
|
||||
** Helpers :noexport:
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: helpers
|
||||
:END:
|
||||
|
@ -230,16 +230,32 @@ Congratulations you should be ready to start now.
|
|||
|
||||
#+begin_notes
|
||||
- There are multiple ways to install Haskell and I don't think there is a
|
||||
full consensus between developer about what is the best method. If you
|
||||
whish to use another method take a look at [[http://haskell.org][haskell.org]].
|
||||
- This install method is only suitable for using as a playground and
|
||||
perfect for this tutorial. I don't think it is suitable for serious
|
||||
development.
|
||||
- =nix= is a generic package manager and goes beyond Haskell. One great
|
||||
good point is that it does not only manage Haskell packages but really a
|
||||
lot of other kind of packages. This can be quite helpful if you need to
|
||||
depends on a Haskell package that itself depends on a system library, for
|
||||
example =ncurses=.
|
||||
full consensus between developer about what is the best method.
|
||||
If you whish to use another method take a look at [[http://haskell.org][haskell.org]].
|
||||
- This install method is only suitable for using as a playground and I
|
||||
think perfectly adapted to run code example from this article.
|
||||
I do not recommend it for serious development.
|
||||
- =nix= is a generic package manager and goes beyond Haskell.
|
||||
One great good point is that it does not only manage Haskell packages but
|
||||
really a lot of other kind of packages.
|
||||
This can be quite helpful if you need to depends on a Haskell package that
|
||||
itself depends on a system library, for example =ncurses=.
|
||||
- I use [[http://nixos.org/nix][=nix=]] for other projects unrelated to Haskell.
|
||||
For example, I use the nix-shell bang pattern for shell script for which
|
||||
I can assume the executable I want are present.
|
||||
#+end_notes
|
||||
|
||||
#+begin_notes
|
||||
*BONUS*: use [[https://direnv.net][=direnv=]]
|
||||
|
||||
#+begin_src
|
||||
~ cd hsenv
|
||||
~ echo "use nix" > .envrc
|
||||
~ direnv allow
|
||||
#+end_src
|
||||
|
||||
Now each time you'll cd into your hsenv directory you'll get the
|
||||
environment set for you.
|
||||
#+end_notes
|
||||
|
||||
** Don't be afraid
|
||||
|
@ -338,7 +354,7 @@ of new things.
|
|||
Hopefully many of these new concepts will help you to program even in
|
||||
imperative languages.
|
||||
|
||||
/Smart Static Typing/
|
||||
/Advanced Static Typing/
|
||||
|
||||
Instead of being in your way like in =C=, =C++= or =Java=, the type system
|
||||
is here to help you.
|
||||
|
@ -455,7 +471,7 @@ We declare the type using =::=
|
|||
#+END_SRC
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
[nix-shell:~/tmp/hsenv]$ runghc basic.hs
|
||||
[nix-shell:~/hsenv]$ runghc basic.hs
|
||||
13
|
||||
#+END_EXAMPLE
|
||||
|
||||
|
@ -472,7 +488,7 @@ Now try
|
|||
You should get this error:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
[nix-shell:~/tmp/hsenv]$ runghc error_basic.hs
|
||||
[nix-shell:~/hsenv]$ runghc error_basic.hs
|
||||
|
||||
error_basic.hs:4:17: error:
|
||||
• No instance for (Fractional Int) arising from the literal ‘2.3’
|
||||
|
@ -497,7 +513,7 @@ infer the most general type for us:
|
|||
#+END_SRC
|
||||
|
||||
#+begin_example
|
||||
[nix-shell:~/tmp/hsenv]$ runghc float_basic.hs
|
||||
[nix-shell:~/hsenv]$ runghc float_basic.hs
|
||||
22.93
|
||||
#+end_example
|
||||
|
||||
|
@ -823,7 +839,7 @@ But it is considered a good practice to do so.
|
|||
|
||||
/Infix notation/
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
#+BEGIN_SRC haskell :tangle functions.hs
|
||||
square :: Num a => a -> a
|
||||
square x = x^2
|
||||
#+END_SRC
|
||||
|
@ -832,7 +848,7 @@ Note =^= uses infix notation.
|
|||
For each infix operator there its associated prefix notation.
|
||||
You just have to put it inside parenthesis.
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
#+BEGIN_SRC haskell :tangle functions.hs
|
||||
square' x = (^) x 2
|
||||
|
||||
square'' x = (^2) x
|
||||
|
@ -841,7 +857,7 @@ You just have to put it inside parenthesis.
|
|||
We can remove =x= in the left and right side!
|
||||
It's called η-reduction.
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
#+BEGIN_SRC haskell :tangle functions.hs
|
||||
square''' = (^2)
|
||||
#+END_SRC
|
||||
|
||||
|
@ -852,11 +868,18 @@ Here:
|
|||
=square= ⇔ =square'= ⇔ =square''= ⇔ =square'''=
|
||||
#+END_QUOTE
|
||||
|
||||
Note for each prefix notation you can transform it to infix notation with
|
||||
=`= like this:
|
||||
|
||||
#+begin_example
|
||||
foo x y ↔ x `foo` y
|
||||
#+end_example
|
||||
|
||||
/Tests/
|
||||
|
||||
An implementation of the absolute function.
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
#+BEGIN_SRC haskell :tangle functions.hs
|
||||
absolute :: (Ord a, Num a) => a -> a
|
||||
absolute x = if x >= 0 then x else -x
|
||||
#+END_SRC
|
||||
|
@ -867,7 +890,7 @@ You cannot forget the =else=.
|
|||
|
||||
Another equivalent version:
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
#+BEGIN_SRC haskell :tangle functions.hs
|
||||
absolute' x
|
||||
| x >= 0 = x
|
||||
| otherwise = -x
|
||||
|
@ -878,7 +901,8 @@ Notation warning: indentation is /important/ in Haskell.
|
|||
Like in Python, bad indentation can break your code!
|
||||
#+END_QUOTE
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
{{{lnk(functions.hs)}}}
|
||||
#+BEGIN_SRC haskell :tangle functions.hs
|
||||
main = do
|
||||
print $ square 10
|
||||
print $ square' 10
|
||||
|
@ -890,13 +914,22 @@ Like in Python, bad indentation can break your code!
|
|||
print $ absolute' (-10)
|
||||
#+END_SRC
|
||||
|
||||
* Difficulty: Normal
|
||||
#+begin_example
|
||||
~/t/hsenv> runghc functions.hs
|
||||
100
|
||||
100
|
||||
100
|
||||
100
|
||||
10
|
||||
10
|
||||
10
|
||||
10
|
||||
#+end_example
|
||||
|
||||
* Difficulty: First steps
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: hard-part
|
||||
:CUSTOM_ID: difficulty--first-steps
|
||||
:END:
|
||||
|
||||
The hard part can now begin.
|
||||
|
||||
** Functional style
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: functional-style
|
||||
|
@ -920,7 +953,7 @@ 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):
|
||||
start by providing an imperative solution (in javascript):
|
||||
|
||||
#+BEGIN_SRC javascript
|
||||
function evenSum(list) {
|
||||
|
@ -1010,12 +1043,11 @@ Note that for any non empty list =l=, =l ⇔ (head l):(tail l)=
|
|||
The first Haskell solution.
|
||||
The function =evenSum= returns the sum of all even numbers in a list:
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
{{{lnk(evenSum_v1.hs)}}}
|
||||
#+BEGIN_SRC haskell :tangle evenSum_v1.hs
|
||||
-- Version 1
|
||||
evenSum :: [Integer] -> Integer
|
||||
|
||||
evenSum l = accumSum 0 l
|
||||
|
||||
accumSum n l = if l == []
|
||||
then n
|
||||
else let x = head l
|
||||
|
@ -1027,39 +1059,36 @@ The function =evenSum= returns the sum of all even numbers in a list:
|
|||
|
||||
To test a function you can use =ghci=:
|
||||
|
||||
#+BEGIN_HTML
|
||||
% ghci
|
||||
GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help
|
||||
Loading package ghc-prim ... linking ... done.
|
||||
Loading package integer-gmp ... linking ... done.
|
||||
Loading package base ... linking ... done.
|
||||
Prelude> :load 11_Functions.lhs
|
||||
[1 of 1] Compiling Main ( 11_Functions.lhs, interpreted )
|
||||
Ok, modules loaded: Main.
|
||||
*Main> evenSum [1..5]
|
||||
6
|
||||
#+END_HTML
|
||||
#+begin_example
|
||||
~/t/hsenv> ghci
|
||||
GHCi, version 8.6.5: http://www.haskell.org/ghc/ :? for help
|
||||
Prelude> :l evenSum_v1.hs
|
||||
[1 of 1] Compiling Main ( evenSum_v1.hs, interpreted )
|
||||
Ok, one module loaded.
|
||||
*Main> evenSum [1..5]
|
||||
6
|
||||
#+end_example
|
||||
|
||||
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
|
||||
#+begin_example
|
||||
*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_example
|
||||
|
||||
Coming from an imperative language all should seem right.
|
||||
In fact, many things can be improved here.
|
||||
|
@ -1069,17 +1098,14 @@ First, we can generalize the type.
|
|||
evenSum :: Integral a => [a] -> a
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
main = do print $ evenSum [1..10]
|
||||
#+END_SRC
|
||||
|
||||
Next, we can use sub functions using =where= or =let=.
|
||||
This way our =accumSum= function won't pollute the namespace of our module.
|
||||
This way our =accumSum= function will not pollute the namespace of our
|
||||
module.
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
{{{lnk(evenSum_v2.hs)}}}
|
||||
#+BEGIN_SRC haskell :tangle evenSum_v2.hs
|
||||
-- Version 2
|
||||
evenSum :: Integral a => [a] -> a
|
||||
|
||||
evenSum l = accumSum 0 l
|
||||
where accumSum n l =
|
||||
if l == []
|
||||
|
@ -1091,15 +1117,10 @@ This way our =accumSum= function won't pollute the namespace of our module.
|
|||
else accumSum n xs
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
main = print $ evenSum [1..10]
|
||||
#+END_SRC
|
||||
|
||||
-----
|
||||
|
||||
Next, we can use pattern matching.
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
{{{lnk(evenSum_v3.hs)}}}
|
||||
#+BEGIN_SRC haskell :tangle evenSum_v3.hs
|
||||
-- Version 3
|
||||
evenSum l = accumSum 0 l
|
||||
where
|
||||
|
@ -1143,10 +1164,6 @@ with
|
|||
This is a very useful feature.
|
||||
It makes our code both terser and easier to read.
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
main = print $ evenSum [1..10]
|
||||
#+END_SRC
|
||||
|
||||
In Haskell you can simplify function definitions by η-reducing them.
|
||||
For example, instead of writing:
|
||||
|
||||
|
@ -1157,15 +1174,15 @@ For example, instead of writing:
|
|||
you can simply write
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
f = some expression
|
||||
f = (some expression)
|
||||
#+END_SRC
|
||||
|
||||
We use this method to remove the =l=:
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
{{{lnk(evenSum_v4.hs)}}}
|
||||
#+BEGIN_SRC haskell :tangle evenSum_v4.hs
|
||||
-- Version 4
|
||||
evenSum :: Integral a => [a] -> a
|
||||
|
||||
evenSum = accumSum 0
|
||||
where
|
||||
accumSum n [] = n
|
||||
|
@ -1175,10 +1192,6 @@ We use this method to remove the =l=:
|
|||
else accumSum n xs
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
main = print $ evenSum [1..10]
|
||||
#+END_SRC
|
||||
|
||||
*** Higher Order Functions
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: higher-order-functions
|
||||
|
@ -1201,7 +1214,8 @@ Here are some examples:
|
|||
|
||||
Let's proceed by small steps.
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
{{{lnk(evenSum_v5.hs)}}}
|
||||
#+BEGIN_SRC haskell :tangle evenSum_v5.hs
|
||||
-- Version 5
|
||||
evenSum l = mysum 0 (filter even l)
|
||||
where
|
||||
|
@ -1218,7 +1232,7 @@ where
|
|||
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=.
|
||||
=True=.
|
||||
|
||||
Our next step is to use another technique to accomplish the same thing as a
|
||||
loop.
|
||||
|
@ -1260,7 +1274,8 @@ follow the code as if =foldl= and =foldl'= were identical.
|
|||
|
||||
Now our new version of =evenSum= becomes:
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
{{{lnk(evenSum_v6.hs)}}}
|
||||
#+BEGIN_SRC haskell :tangle evenSum_v6.hs
|
||||
-- Version 6
|
||||
-- foldl' isn't accessible by default
|
||||
-- we need to import it from the module Data.List
|
||||
|
@ -1272,7 +1287,8 @@ Now our new version of =evenSum= becomes:
|
|||
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
|
||||
{{{lnk(evenSum_v7.hs)}}}
|
||||
#+BEGIN_SRC haskell :tangle evenSum_v7.hs
|
||||
-- Version 7
|
||||
-- Generally it is considered a good practice
|
||||
-- to import only the necessary function(s)
|
||||
|
@ -1286,15 +1302,10 @@ And of course, we note that
|
|||
(\x y -> x+y) ⇔ (+)
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
main = print $ evenSum [1..10]
|
||||
#+END_SRC
|
||||
|
||||
-----
|
||||
|
||||
Finally
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
{{{lnk(evenSum_v8.hs)}}}
|
||||
#+BEGIN_SRC haskell :tangle evenSum_v8.hs
|
||||
-- Version 8
|
||||
import Data.List (foldl')
|
||||
evenSum :: Integral a => [a] -> a
|
||||
|
@ -1327,7 +1338,8 @@ The =(.)= function corresponds to mathematical composition.
|
|||
|
||||
We can take advantage of this operator to η-reduce our function:
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
{{{lnk(evenSum_v9.hs)}}}
|
||||
#+BEGIN_SRC haskell :tangle evenSum_v9.hs
|
||||
-- Version 9
|
||||
import Data.List (foldl')
|
||||
evenSum :: Integral a => [a] -> a
|
||||
|
@ -1336,7 +1348,8 @@ We can take advantage of this operator to η-reduce our function:
|
|||
|
||||
Also, we could rename some parts to make it clearer:
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
{{{lnk(evenSum_v10.hs)}}}
|
||||
#+BEGIN_SRC haskell :tangle evenSum_v10.hs
|
||||
-- Version 10
|
||||
import Data.List (foldl')
|
||||
sum' :: (Num a) => [a] -> a
|
||||
|
@ -1365,7 +1378,7 @@ Updating version 10 is extremely easy:
|
|||
squareEvenSum' = evenSum . (map (^2))
|
||||
#+END_SRC
|
||||
|
||||
We just had to add another "transformation function"[^0216].
|
||||
We just had to add another "transformation function".
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
map (^2) [1,2,3,4] ⇔ [1,4,9,16]
|
||||
|
@ -1375,9 +1388,9 @@ 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.
|
||||
But in addition you can think more mathematically about your functions.
|
||||
You can also use your functions interchangeably 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 ☺.
|
||||
|
||||
|
@ -1394,7 +1407,7 @@ 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
|
||||
One of the great powers of Haskell is the ability to create DSL (Domain
|
||||
Specific Language) making it easy to change the programming paradigm.
|
||||
|
||||
In fact, Haskell is also great when you want to write imperative style
|
||||
|
@ -1409,10 +1422,6 @@ 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
|
||||
main = print $ evenSum [1..10]
|
||||
#+END_SRC
|
||||
|
||||
** Types
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: types
|
||||
|
@ -1421,8 +1430,10 @@ another essential aspect of Haskell: /Types/.
|
|||
#+CAPTION: Dali, the madonna of port Lligat
|
||||
[[./salvador-dali-the-madonna-of-port-lligat.jpg]]
|
||||
|
||||
#+MACRO: tldr @@html:<abbr title="too long; didn't read">tl;dr:</abbr> @@
|
||||
|
||||
#+BEGIN_QUOTE
|
||||
%tldr
|
||||
{{{tldr}}}
|
||||
|
||||
- =type Name = AnotherType= is just an alias and the compiler doesn't
|
||||
mark any difference between =Name= and =AnotherType=.
|
||||
|
@ -1436,8 +1447,8 @@ 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
|
||||
And the main reason is because of the type checking during compilation.
|
||||
Type checking makes it easy to detect where you used the wrong parameter
|
||||
at the wrong place, for example.
|
||||
|
||||
*** Type inference
|
||||
|
@ -1461,15 +1472,13 @@ You can provide =square= with an =Int=, an =Integer=, a =Float= a
|
|||
Proof by example:
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
% ghci
|
||||
GHCi, version 7.0.4:
|
||||
...
|
||||
Prelude> let square x = x*x
|
||||
~/t/hsenv> ghci
|
||||
GHCi, version 8.6.5: http://www.haskell.org/ghc/ :? for help
|
||||
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
|
||||
|
@ -1481,15 +1490,12 @@ 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
|
||||
|
@ -1524,8 +1530,8 @@ int main() {
|
|||
#+END_SRC
|
||||
|
||||
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.
|
||||
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.
|
||||
|
@ -1549,7 +1555,8 @@ Generally, in Haskell:
|
|||
You can construct your own types.
|
||||
First, you can use aliases or type synonyms.
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
{{{lnk(type_constr_1.hs)}}}
|
||||
#+BEGIN_SRC haskell :tangle type_constr_1.hs
|
||||
type Name = String
|
||||
type Color = String
|
||||
|
||||
|
@ -1591,7 +1598,7 @@ Another method is to create your own types using the keyword =data=.
|
|||
|
||||
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.
|
||||
is to be a bit more verbose.
|
||||
|
||||
Also notice that constructors are functions:
|
||||
|
||||
|
@ -1666,7 +1673,7 @@ 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
|
||||
#+BEGIN_SRC haskell :tangle list.hs
|
||||
infixr 5 :::
|
||||
data List a = Nil | a ::: (List a)
|
||||
deriving (Show,Read,Eq,Ord)
|
||||
|
@ -1676,12 +1683,12 @@ 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
|
||||
#+BEGIN_SRC haskell :tangle list.hs
|
||||
convertList [] = Nil
|
||||
convertList (x:xs) = x ::: convertList xs
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
#+BEGIN_SRC haskell :tangle list.hs
|
||||
main = do
|
||||
print (0 ::: 1 ::: Nil)
|
||||
print (convertList [0,1])
|
||||
|
@ -1704,9 +1711,7 @@ This prints:
|
|||
|
||||
We'll just give another standard example: binary trees.
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
import Data.List
|
||||
|
||||
#+BEGIN_SRC haskell :tangle tree.hs
|
||||
data BinTree a = Empty
|
||||
| Node a (BinTree a) (BinTree a)
|
||||
deriving (Show)
|
||||
|
@ -1715,7 +1720,7 @@ We'll just give another standard example: binary trees.
|
|||
We will also create a function which turns a list into an ordered binary
|
||||
tree.
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
#+BEGIN_SRC haskell :tangle tree.hs
|
||||
treeFromList :: (Ord a) => [a] -> BinTree a
|
||||
treeFromList [] = Empty
|
||||
treeFromList (x:xs) = Node x (treeFromList (filter (<x) xs))
|
||||
|
@ -1733,7 +1738,7 @@ Look at how elegant this function is. In plain English:
|
|||
- the right subtree is the tree created from members of the list =xs=
|
||||
which are strictly superior to =x=.
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
#+BEGIN_SRC haskell :tangle tree.hs
|
||||
main = print $ treeFromList [7,2,4,8]
|
||||
#+END_SRC
|
||||
|
||||
|
@ -1745,212 +1750,106 @@ Node 7 (Node 2 Empty (Node 4 Empty Empty)) (Node 8 Empty Empty)
|
|||
|
||||
This is an informative but quite unpleasant representation of our tree.
|
||||
|
||||
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.
|
||||
I've added the =containers= package in the =shell.nix= file, it is time to
|
||||
use this library which contain an helper to show trees.
|
||||
|
||||
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 :tangle pretty_tree.hs
|
||||
import Data.Tree (Tree,Forest(..))
|
||||
import qualified Data.Tree as Tree
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
data BinTree a = Empty
|
||||
| Node a (BinTree a) (BinTree a)
|
||||
deriving (Eq,Ord)
|
||||
data BinTree a = Empty
|
||||
| Node a (BinTree a) (BinTree a)
|
||||
deriving (Eq,Ord,Show)
|
||||
|
||||
treeFromList :: (Ord a) => [a] -> BinTree a
|
||||
treeFromList [] = Empty
|
||||
treeFromList (x:xs) = Node x (treeFromList (filter (<x) xs))
|
||||
(treeFromList (filter (>x) xs))
|
||||
|
||||
-- | Function to transform our internal BinTree type to the
|
||||
-- type of Tree declared in Data.Tree (from containers package)
|
||||
-- so that the function Tree.drawForest can use
|
||||
binTreeToForestString :: (Show a) => BinTree a -> Forest String
|
||||
binTreeToForestString Empty = []
|
||||
binTreeToForestString (Node x left right) =
|
||||
[Tree.Node (show x) ((binTreeToForestString left) ++ (binTreeToForestString right))]
|
||||
|
||||
-- | Function that given a BinTree print a representation of it in the console
|
||||
prettyPrintTree :: (Show a) => BinTree a -> IO ()
|
||||
prettyPrintTree = putStrLn . Tree.drawForest . binTreeToForestString
|
||||
|
||||
main = do
|
||||
putStrLn "Int binary tree:"
|
||||
prettyPrintTree $ treeFromList [7,2,4,8,1,3,6,21,12,23]
|
||||
putStrLn "\nNote we could also use another type\n"
|
||||
putStrLn "String binary tree:"
|
||||
prettyPrintTree $
|
||||
treeFromList ["foo","bar","baz","gor","yog"]
|
||||
putStrLn "\nAs we can test equality and order trees, we can make tree of trees!\n"
|
||||
putStrLn "\nBinary tree of Char binary trees:"
|
||||
prettyPrintTree (treeFromList
|
||||
(map treeFromList ["foo","bar","zara","baz","foo"]))
|
||||
#+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
|
||||
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
|
||||
-- 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
|
||||
treeFromList :: (Ord a) => [a] -> BinTree a
|
||||
treeFromList [] = Empty
|
||||
treeFromList (x:xs) = Node x (treeFromList (filter (<x) xs))
|
||||
(treeFromList (filter (>x) xs))
|
||||
#+END_SRC
|
||||
|
||||
And now, we can play:
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
main = do
|
||||
putStrLn "Int binary tree:"
|
||||
print $ treeFromList [7,2,4,8,1,3,6,21,12,23]
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
#+begin_example
|
||||
~/t/hsenv> runghc pretty_tree.hs
|
||||
Int binary tree:
|
||||
< 7
|
||||
: |--2
|
||||
: | |--1
|
||||
: | `--4
|
||||
: | |--3
|
||||
: | `--6
|
||||
: `--8
|
||||
: `--21
|
||||
: |--12
|
||||
: `--23
|
||||
#+END_EXAMPLE
|
||||
7
|
||||
|
|
||||
+- 2
|
||||
| |
|
||||
| +- 1
|
||||
| |
|
||||
| `- 4
|
||||
| |
|
||||
| +- 3
|
||||
| |
|
||||
| `- 6
|
||||
|
|
||||
`- 8
|
||||
|
|
||||
`- 21
|
||||
|
|
||||
+- 12
|
||||
|
|
||||
`- 23
|
||||
|
||||
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
|
||||
putStrLn "\nString binary tree:"
|
||||
print $ treeFromList ["foo","bar","baz","gor","yog"]
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_EXAMPLE
|
||||
Note we could also use another type
|
||||
|
||||
String binary tree:
|
||||
< "foo"
|
||||
: |--"bar"
|
||||
: | `--"baz"
|
||||
: `--"gor"
|
||||
: `--"yog"
|
||||
#+END_EXAMPLE
|
||||
"foo"
|
||||
|
|
||||
+- "bar"
|
||||
| |
|
||||
| `- "baz"
|
||||
|
|
||||
`- "gor"
|
||||
|
|
||||
`- "yog"
|
||||
|
||||
|
||||
|
||||
As we can test equality and order trees, we can make tree of trees!
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
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
|
||||
Node 'f' Empty (Node 'o' Empty Empty)
|
||||
|
|
||||
+- Node 'b' (Node 'a' Empty Empty) (Node 'r' Empty Empty)
|
||||
| |
|
||||
| `- Node 'b' (Node 'a' Empty Empty) (Node 'z' Empty Empty)
|
||||
|
|
||||
`- Node 'z' (Node 'a' Empty (Node 'r' Empty Empty)) Empty
|
||||
#+end_example
|
||||
|
||||
This is why I chose to prefix each line of tree display by =:= (except
|
||||
for the root).
|
||||
|
||||
#+CAPTION: Yo Dawg Tree
|
||||
[[./yo_dawg_tree.jpg]]
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
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
|
||||
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"=.
|
||||
Notice how duplicate elements aren't inserted in trees.
|
||||
For exemple the Char BinTree constructed from the list =foo= is just =f ->
|
||||
o=.
|
||||
When =o= is inserted another time the second =o= is not duplicated.
|
||||
But more importantly it works also for our own =BinTree= notice how the
|
||||
tree for =foo= is inserted only once.
|
||||
We have this for (almost) free, because we have declared Tree to be an
|
||||
instance of =Eq=.
|
||||
|
||||
|
@ -2023,46 +1922,6 @@ This code is mostly the same as the previous one.
|
|||
deriving (Eq,Ord)
|
||||
#+END_SRC
|
||||
|
||||
#+BEGIN_SRC haskell
|
||||
-- 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:
|
||||
|
||||
|
@ -2178,7 +2037,7 @@ Look at the result for
|
|||
print $ treeTakeDepth 4 infTreeTwo
|
||||
#+END_SRC
|
||||
|
||||
* Difficulty: Nightmare
|
||||
* Difficulty: Hard
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: hell-difficulty-part
|
||||
:END:
|
||||
|
@ -3219,7 +3078,7 @@ In particular, monads are very useful for:
|
|||
If you have followed me until here, then you've done it! You know
|
||||
monads[fn:7]!
|
||||
|
||||
* Difficulty: Hell
|
||||
* Difficulty: Nightmarish
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: difficulty--hell
|
||||
:END:
|
||||
|
@ -3249,6 +3108,13 @@ Haskell at least two or three times before it really clicked for them.
|
|||
:CUSTOM_ID: web-application
|
||||
:END:
|
||||
|
||||
* Difficulty: Hell
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: difficulty--hell-be9a
|
||||
:END:
|
||||
|
||||
This part will be for advanced Haskell code.
|
||||
|
||||
* Appendix
|
||||
:PROPERTIES:
|
||||
:CUSTOM_ID: appendix
|
||||
|
|
10
src/posts/0010-Haskell-Now/list.hs
Normal file
10
src/posts/0010-Haskell-Now/list.hs
Normal file
|
@ -0,0 +1,10 @@
|
|||
infixr 5 :::
|
||||
data List a = Nil | a ::: (List a)
|
||||
deriving (Show,Read,Eq,Ord)
|
||||
|
||||
convertList [] = Nil
|
||||
convertList (x:xs) = x ::: convertList xs
|
||||
|
||||
main = do
|
||||
print (0 ::: 1 ::: Nil)
|
||||
print (convertList [0,1])
|
35
src/posts/0010-Haskell-Now/pretty_tree.hs
Normal file
35
src/posts/0010-Haskell-Now/pretty_tree.hs
Normal file
|
@ -0,0 +1,35 @@
|
|||
import Data.Tree (Tree,Forest(..))
|
||||
import qualified Data.Tree as Tree
|
||||
|
||||
data BinTree a = Empty
|
||||
| Node a (BinTree a) (BinTree a)
|
||||
deriving (Eq,Ord,Show)
|
||||
|
||||
treeFromList :: (Ord a) => [a] -> BinTree a
|
||||
treeFromList [] = Empty
|
||||
treeFromList (x:xs) = Node x (treeFromList (filter (<x) xs))
|
||||
(treeFromList (filter (>x) xs))
|
||||
|
||||
-- | Function to transform our internal BinTree type to the
|
||||
-- type of Tree declared in Data.Tree (from containers package)
|
||||
-- so that the function Tree.drawForest can use
|
||||
binTreeToForestString :: (Show a) => BinTree a -> Forest String
|
||||
binTreeToForestString Empty = []
|
||||
binTreeToForestString (Node x left right) =
|
||||
[Tree.Node (show x) ((binTreeToForestString left) ++ (binTreeToForestString right))]
|
||||
|
||||
-- | Function that given a BinTree print a representation of it in the console
|
||||
prettyPrintTree :: (Show a) => BinTree a -> IO ()
|
||||
prettyPrintTree = putStrLn . Tree.drawForest . binTreeToForestString
|
||||
|
||||
main = do
|
||||
putStrLn "Int binary tree:"
|
||||
prettyPrintTree $ treeFromList [7,2,4,8,1,3,6,21,12,23]
|
||||
putStrLn "\nNote we could also use another type\n"
|
||||
putStrLn "String binary tree:"
|
||||
prettyPrintTree $
|
||||
treeFromList ["foo","bar","baz","gor","yog"]
|
||||
putStrLn "\nAs we can test equality and order trees, we can make tree of trees!\n"
|
||||
putStrLn "\nBinary tree of Char binary trees:"
|
||||
prettyPrintTree (treeFromList
|
||||
(map treeFromList ["foo","bar","zara","baz","foo"]))
|
10
src/posts/0010-Haskell-Now/tree.hs
Normal file
10
src/posts/0010-Haskell-Now/tree.hs
Normal file
|
@ -0,0 +1,10 @@
|
|||
data BinTree a = Empty
|
||||
| Node a (BinTree a) (BinTree a)
|
||||
deriving (Show)
|
||||
|
||||
treeFromList :: (Ord a) => [a] -> BinTree a
|
||||
treeFromList [] = Empty
|
||||
treeFromList (x:xs) = Node x (treeFromList (filter (<x) xs))
|
||||
(treeFromList (filter (>x) xs))
|
||||
|
||||
main = print $ treeFromList [7,2,4,8]
|
11
src/posts/0010-Haskell-Now/type_constr_1.hs
Normal file
11
src/posts/0010-Haskell-Now/type_constr_1.hs
Normal file
|
@ -0,0 +1,11 @@
|
|||
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
|
Loading…
Reference in a new issue