progress
This commit is contained in:
parent
cc7ee03907
commit
250335f16b
10 changed files with 682 additions and 594 deletions
|
@ -2,13 +2,19 @@
|
||||||
Author: Yann Esposito
|
Author: Yann Esposito
|
||||||
*/
|
*/
|
||||||
/* Fonts */
|
/* Fonts */
|
||||||
|
:root {
|
||||||
|
--lh: 16px;
|
||||||
|
}
|
||||||
body {
|
body {
|
||||||
font: 14px/1.4 monospace;
|
font: 14px/1.4 monospace;
|
||||||
line-height: 16px;
|
line-height: var(--lh);
|
||||||
}
|
}
|
||||||
pre, pre code {
|
pre, pre code {
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
}
|
}
|
||||||
|
blockquote pre {
|
||||||
|
line-height: var(--lh);
|
||||||
|
}
|
||||||
/* Layout */
|
/* Layout */
|
||||||
body, h1, h2, h3, h4, h5, h6, pre, code, blockquote, ol, ul, ol ol, ul ul, ul ol, ol
|
body, h1, h2, h3, h4, h5, h6, pre, code, blockquote, ol, ul, ol ol, ul ul, ul ol, ol
|
||||||
ul, li, p, section, header, footer, img {
|
ul, li, p, section, header, footer, img {
|
||||||
|
@ -20,8 +26,8 @@ ul, li, p, section, header, footer, img {
|
||||||
}
|
}
|
||||||
h1, h2, h3, h4, h5, h6, pre, code, blockquote, p, ul, ol, section, header,
|
h1, h2, h3, h4, h5, h6, pre, code, blockquote, p, ul, ol, section, header,
|
||||||
figure,table {
|
figure,table {
|
||||||
margin-top: 1em;
|
margin-top: var(--lh);
|
||||||
margin-bottom: 1em;
|
margin-bottom: var(--lh);
|
||||||
}
|
}
|
||||||
li {
|
li {
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -122,7 +128,7 @@ hr {
|
||||||
margin:0;
|
margin:0;
|
||||||
}
|
}
|
||||||
#table-of-contents {
|
#table-of-contents {
|
||||||
margin-bottom: 1em;
|
margin-bottom: var(--lh);
|
||||||
}
|
}
|
||||||
#postamble:before, hr:after {
|
#postamble:before, hr:after {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -186,7 +192,7 @@ figure, .figure {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
}
|
}
|
||||||
#postamble {
|
#postamble {
|
||||||
margin-top: 1em;
|
margin-top: var(--lh);
|
||||||
}
|
}
|
||||||
.timestamp-wrapper {
|
.timestamp-wrapper {
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
@ -252,9 +258,9 @@ figure, .figure {
|
||||||
@media (prefers-color-scheme: light) {
|
@media (prefers-color-scheme: light) {
|
||||||
:root {
|
:root {
|
||||||
--bg: var(--b3);
|
--bg: var(--b3);
|
||||||
--fg: var(--b00);
|
--fg: var(--b01);
|
||||||
--bg2: var(--b2);
|
--bg2: var(--b2);
|
||||||
--fg2: var(--b1);
|
--fg2: var(--b00);
|
||||||
--rfg: var(--b01);
|
--rfg: var(--b01);
|
||||||
--rbg: var(--b2);
|
--rbg: var(--b2);
|
||||||
--bdr: var(--b2);
|
--bdr: var(--b2);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
fib :: [Integer]
|
fib :: [Integer]
|
||||||
fib = 1:1:zipWith (+) fib (tail fib)
|
fib = 1:1:zipWith (+) fib (tail fib)
|
||||||
|
|
||||||
main = traverse_ print (take 20 (drop 200 fib))
|
main = traverse print (take 20 (drop 200 fib))
|
||||||
|
|
11
src/posts/0010-Haskell-Now/fib_lazy_trace.hs
Normal file
11
src/posts/0010-Haskell-Now/fib_lazy_trace.hs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import Debug.Trace
|
||||||
|
|
||||||
|
-- like + but each time this is evaluated print a trace
|
||||||
|
tracedPlus x y = trace ("> " ++ show x ++ " + " ++ show y) (x + y)
|
||||||
|
|
||||||
|
fib :: [Integer]
|
||||||
|
fib = 1:1:zipWith tracedPlus fib (tail fib)
|
||||||
|
|
||||||
|
main = do
|
||||||
|
print (fib !! 10)
|
||||||
|
print (fib !! 12)
|
|
@ -6,6 +6,7 @@
|
||||||
#+keywords: Haskell, programming, functional, tutorial |
|
#+keywords: Haskell, programming, functional, tutorial |
|
||||||
#+DESCRIPTION: A very dense introduction and Haskell tutorial. Brace yourself.
|
#+DESCRIPTION: A very dense introduction and Haskell tutorial. Brace yourself.
|
||||||
#+OPTIONS: auto-id:t toc:t
|
#+OPTIONS: auto-id:t toc:t
|
||||||
|
#+STARTUP: overview
|
||||||
|
|
||||||
#+begin_notes
|
#+begin_notes
|
||||||
A very short and intense introduction to Haskell.
|
A very short and intense introduction to Haskell.
|
||||||
|
@ -529,7 +530,7 @@ For example, in =C=, you'll have to declare a function for =int=, for
|
||||||
But, what type should we declare?
|
But, what type should we declare?
|
||||||
To discover the type Haskell has found for us, just launch ghci:
|
To discover the type Haskell has found for us, just launch ghci:
|
||||||
|
|
||||||
#+BEGIN_SRC
|
#+BEGIN_EXAMPLE
|
||||||
% ghci
|
% ghci
|
||||||
GHCi, version 7.0.4: http://www.haskell.org/ghc/ :? for help
|
GHCi, version 7.0.4: http://www.haskell.org/ghc/ :? for help
|
||||||
Loading package ghc-prim ... linking ... done.
|
Loading package ghc-prim ... linking ... done.
|
||||||
|
@ -539,13 +540,13 @@ To discover the type Haskell has found for us, just launch ghci:
|
||||||
Prelude> let f x y = x*x + y*y
|
Prelude> let f x y = x*x + y*y
|
||||||
Prelude> :type f
|
Prelude> :type f
|
||||||
f :: Num a => a -> a -> a
|
f :: Num a => a -> a -> a
|
||||||
#+END_SRC
|
#+END_EXAMPLE
|
||||||
|
|
||||||
Uh? What is this strange type?
|
Uh? What is this strange type?
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
#+BEGIN_SRC haskell
|
||||||
Num a => a -> a -> a
|
Num a => a -> a -> a
|
||||||
#+END_EXAMPLE
|
#+END_SRC
|
||||||
|
|
||||||
First, let's focus on the right part =a -> a -> a=.
|
First, let's focus on the right part =a -> a -> a=.
|
||||||
To understand it, just look at a list of progressive examples:
|
To understand it, just look at a list of progressive examples:
|
||||||
|
@ -1912,23 +1913,18 @@ Also, note in Haskell there is a notation for infinite lists
|
||||||
and most functions will work with them. Also, there is a built-in
|
and most functions will work with them. Also, there is a built-in
|
||||||
function =take= which is equivalent to our =take'=.
|
function =take= which is equivalent to our =take'=.
|
||||||
|
|
||||||
This code is mostly the same as the previous one.
|
*** Infinite Trees
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: infinite-trees
|
||||||
|
:END:
|
||||||
|
|
||||||
#+begin_src haskell :tangle infinite_tree.hs :exports none
|
#+begin_src haskell :tangle infinite_tree.hs :exports none
|
||||||
import Data.Tree (Tree,Forest(..))
|
import Data.Tree (Tree,Forest(..))
|
||||||
import qualified Data.Tree as Tree
|
import qualified Data.Tree as Tree
|
||||||
|
|
||||||
#+end_src
|
|
||||||
|
|
||||||
|
|
||||||
#+BEGIN_SRC haskell :tangle infinite_tree.hs
|
|
||||||
data BinTree a = Empty
|
data BinTree a = Empty
|
||||||
| Node a (BinTree a) (BinTree a)
|
| Node a (BinTree a) (BinTree a)
|
||||||
deriving (Eq,Ord,Show)
|
deriving (Eq,Ord,Show)
|
||||||
#+END_SRC
|
|
||||||
|
|
||||||
|
|
||||||
#+begin_src haskell :tangle infinite_tree.hs :exports none
|
|
||||||
|
|
||||||
-- | Function to transform our internal BinTree type to the
|
-- | Function to transform our internal BinTree type to the
|
||||||
-- type of Tree declared in Data.Tree (from containers package)
|
-- type of Tree declared in Data.Tree (from containers package)
|
||||||
|
@ -1941,7 +1937,6 @@ This code is mostly the same as the previous one.
|
||||||
-- | Function that given a BinTree print a representation of it in the console
|
-- | Function that given a BinTree print a representation of it in the console
|
||||||
prettyPrintTree :: (Show a) => BinTree a -> IO ()
|
prettyPrintTree :: (Show a) => BinTree a -> IO ()
|
||||||
prettyPrintTree = putStrLn . Tree.drawForest . binTreeToForestString
|
prettyPrintTree = putStrLn . Tree.drawForest . binTreeToForestString
|
||||||
|
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
|
@ -2119,7 +2114,11 @@ Look at the result for
|
||||||
`- 3
|
`- 3
|
||||||
#+END_EXAMPLE
|
#+END_EXAMPLE
|
||||||
|
|
||||||
#+begin_notes
|
*** Fibonnacci infinite list
|
||||||
|
:PROPERTIES:
|
||||||
|
:CUSTOM_ID: fibonnacci-infinite-list
|
||||||
|
:END:
|
||||||
|
|
||||||
The important things to remember.
|
The important things to remember.
|
||||||
Haskell handle infinite structures naturally mostly because it is not strict.
|
Haskell handle infinite structures naturally mostly because it is not strict.
|
||||||
|
|
||||||
|
@ -2130,19 +2129,17 @@ like this common example:
|
||||||
fib :: [Integer]
|
fib :: [Integer]
|
||||||
fib = 1:1:zipWith (+) fib (tail fib)
|
fib = 1:1:zipWith (+) fib (tail fib)
|
||||||
|
|
||||||
main = traverse_ print (take 20 (drop 200 fib))
|
main = traverse print (take 20 (drop 200 fib))
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
Many new details in this small code. Don't worry if you do not get all details:
|
Many new details in this small code. Don't worry if you do not get all details:
|
||||||
|
|
||||||
- =fib= is a list of Integer, not a function
|
- =fib= is a list of Integer, not a function
|
||||||
- =(!!)= is used to get the nth element of a list.
|
|
||||||
- =drop n= remove n element of a list
|
- =drop n= remove n element of a list
|
||||||
- =take n= keep the first n elements of a list
|
- =take n= keep the first n elements of a list
|
||||||
- =zipWith op [a1,a2,a3,...] [b1,b2,b3,...]= will generate the list
|
- =zipWith op [a1,a2,a3,...] [b1,b2,b3,...]= will generate the list
|
||||||
=[op a1 b1,op a2 b2,op a3 b3, .... ]=
|
=[op a1 b1,op a2 b2,op a3 b3, .... ]=
|
||||||
- =traverse_= is like map but for performing effects (in this case print)
|
- =traverse= is like map but for performing effects (in this case print)
|
||||||
and discarding any result if any.
|
|
||||||
|
|
||||||
This progam print all fibonnacci numbers from 201 to 221 instantaneously.
|
This progam print all fibonnacci numbers from 201 to 221 instantaneously.
|
||||||
Because, =fib= is a list that will be used as "cache" to compute each
|
Because, =fib= is a list that will be used as "cache" to compute each
|
||||||
|
@ -2176,7 +2173,49 @@ user 0m0.192s
|
||||||
sys 0m0.058s
|
sys 0m0.058s
|
||||||
#+end_example
|
#+end_example
|
||||||
|
|
||||||
#+end_notes
|
Let's see how this work using =Debug.Trace=:
|
||||||
|
|
||||||
|
{{{lnk(fib_lazy_trace.hs)}}}
|
||||||
|
#+begin_src haskell :tangle fib_lazy_trace.hs
|
||||||
|
import Debug.Trace
|
||||||
|
|
||||||
|
-- like + but each time this is evaluated print a trace
|
||||||
|
tracedPlus x y = trace ("> " ++ show x ++ " + " ++ show y) (x + y)
|
||||||
|
|
||||||
|
fib :: [Integer]
|
||||||
|
fib = 1:1:zipWith tracedPlus fib (tail fib)
|
||||||
|
|
||||||
|
main = do
|
||||||
|
print (fib !! 10)
|
||||||
|
print (fib !! 12)
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
[hs:hsenv]> runghc fib_lazy_trace.hs
|
||||||
|
> 1 + 1
|
||||||
|
> 1 + 2
|
||||||
|
> 2 + 3
|
||||||
|
> 3 + 5
|
||||||
|
> 5 + 8
|
||||||
|
> 8 + 13
|
||||||
|
> 13 + 21
|
||||||
|
> 21 + 34
|
||||||
|
> 34 + 55
|
||||||
|
89
|
||||||
|
> 55 + 89
|
||||||
|
> 89 + 144
|
||||||
|
233
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
Notice how, once computed, the list is kept in memory.
|
||||||
|
This is why when the second time we ask for the 12th element of fib we only
|
||||||
|
perform two more additions.
|
||||||
|
This is both a blessing and a curse.
|
||||||
|
A blessing if you know when to use this as in this example.
|
||||||
|
And a curse as if do not take care about lazyness it will come back at you
|
||||||
|
with memory leaks.
|
||||||
|
|
||||||
|
After a bit of experience, most Haskellers can avoid memory leaks naturally.
|
||||||
|
|
||||||
* Difficulty: Hard
|
* Difficulty: Hard
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -2334,6 +2373,7 @@ This is a very common type in Haskell.
|
||||||
|
|
||||||
#+BEGIN_SRC haskell :tangle io_sum_safe.hs
|
#+BEGIN_SRC haskell :tangle io_sum_safe.hs
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import Text.Read (readMaybe)
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
What is this thing?
|
What is this thing?
|
||||||
|
@ -2346,19 +2386,10 @@ Its definition is:
|
||||||
|
|
||||||
This is a nice way to tell there was an error while trying to
|
This is a nice way to tell there was an error while trying to
|
||||||
create/compute a value.
|
create/compute a value.
|
||||||
The =maybeRead= function is a great example of this.
|
The =readMaybe= function is a great example of this.
|
||||||
This is a function similar to the function =read=[fn:4], but if something
|
This is a function similar to the function =read=[fn:4], but if something
|
||||||
goes wrong the returned value is =Nothing=.
|
goes wrong the returned value is =Nothing=.
|
||||||
If the value is right, it returns =Just <the value>=.
|
If the value is right, it returns =Just <the value>=.
|
||||||
Don't try to understand too much of this function.
|
|
||||||
I use a lower level function than =read=: =reads=.
|
|
||||||
|
|
||||||
#+BEGIN_SRC haskell :tangle io_sum_safe.hs
|
|
||||||
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:
|
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=.
|
If the string has the wrong format, it will return =Nothing=.
|
||||||
|
@ -2366,7 +2397,7 @@ Otherwise, for example for "1,2,3", it will return =Just [1,2,3]=.
|
||||||
|
|
||||||
#+BEGIN_SRC haskell :tangle io_sum_safe.hs
|
#+BEGIN_SRC haskell :tangle io_sum_safe.hs
|
||||||
getListFromString :: String -> Maybe [Integer]
|
getListFromString :: String -> Maybe [Integer]
|
||||||
getListFromString str = maybeRead $ "[" ++ str ++ "]"
|
getListFromString str = readMaybe $ "[" ++ str ++ "]"
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
We simply have to test the value in our main function.
|
We simply have to test the value in our main function.
|
||||||
|
@ -2376,7 +2407,7 @@ We simply have to test the value in our main function.
|
||||||
main = do
|
main = do
|
||||||
putStrLn "Enter a list of numbers (separated by comma):"
|
putStrLn "Enter a list of numbers (separated by comma):"
|
||||||
input <- getLine
|
input <- getLine
|
||||||
let maybeList = getListFromString input in
|
let maybeList = getListFromString input
|
||||||
case maybeList of
|
case maybeList of
|
||||||
Just l -> print (sum l)
|
Just l -> print (sum l)
|
||||||
Nothing -> putStrLn "Bad format. Good Bye."
|
Nothing -> putStrLn "Bad format. Good Bye."
|
||||||
|
@ -2411,26 +2442,23 @@ enters a valid answer.
|
||||||
|
|
||||||
We keep the first part:
|
We keep the first part:
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+BEGIN_SRC haskell :tangle io_sum_ask.hs
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import Text.Read (readMaybe)
|
||||||
|
|
||||||
maybeRead :: Read a => String -> Maybe a
|
|
||||||
maybeRead s = case reads s of
|
|
||||||
[(x,"")] -> Just x
|
|
||||||
_ -> Nothing
|
|
||||||
getListFromString :: String -> Maybe [Integer]
|
getListFromString :: String -> Maybe [Integer]
|
||||||
getListFromString str = maybeRead $ "[" ++ str ++ "]"
|
getListFromString str = readMaybe $ "[" ++ str ++ "]"
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
Now we create a function which will ask the user for an list of integers
|
Now we create a function which will ask the user for an list of integers
|
||||||
until the input is right.
|
until the input is right.
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+BEGIN_SRC haskell :tangle io_sum_ask.hs
|
||||||
askUser :: IO [Integer]
|
askUser :: IO [Integer]
|
||||||
askUser = do
|
askUser = do
|
||||||
putStrLn "Enter a list of numbers (separated by comma):"
|
putStrLn "Enter a list of numbers (separated by comma):"
|
||||||
input <- getLine
|
input <- getLine
|
||||||
let maybeList = getListFromString input in
|
let maybeList = getListFromString input
|
||||||
case maybeList of
|
case maybeList of
|
||||||
Just l -> return l
|
Just l -> return l
|
||||||
Nothing -> askUser
|
Nothing -> askUser
|
||||||
|
@ -2442,7 +2470,7 @@ some IO actions.
|
||||||
Some people might explain while waving their hands:
|
Some people might explain while waving their hands:
|
||||||
|
|
||||||
#+BEGIN_QUOTE
|
#+BEGIN_QUOTE
|
||||||
«This is an =[Integer]= inside an =IO=»
|
«This is an =[Integer]= inside an =IO=.»
|
||||||
#+END_QUOTE
|
#+END_QUOTE
|
||||||
|
|
||||||
If you want to understand the details behind all of this, you'll have to
|
If you want to understand the details behind all of this, you'll have to
|
||||||
|
@ -2452,7 +2480,7 @@ remember to think about the type.
|
||||||
|
|
||||||
Finally our main function is much simpler:
|
Finally our main function is much simpler:
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+BEGIN_SRC haskell :tangle io_sum_ask.hs
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
list <- askUser
|
list <- askUser
|
||||||
|
@ -2489,46 +2517,46 @@ If you practice a bit, you should be able to /use/ =IO=.
|
||||||
[[./magritte_pipe.jpg]]
|
[[./magritte_pipe.jpg]]
|
||||||
|
|
||||||
#+BEGIN_QUOTE
|
#+BEGIN_QUOTE
|
||||||
Here is a %tldr for this section.
|
{{{tldr}}}
|
||||||
|
|
||||||
To separate pure and impure parts, =main= is defined as a function
|
To separate pure and impure parts, =main= is defined as a function which
|
||||||
which modifies the state of the world.
|
modifies the state of the world.
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
#+BEGIN_EXAMPLE
|
||||||
main :: World -> World
|
main :: World -> World
|
||||||
#+END_EXAMPLE
|
#+END_EXAMPLE
|
||||||
|
|
||||||
A function is guaranteed to have side effects only if it has this
|
A function is guaranteed to have side effects only if it has this type.
|
||||||
type. But look at a typical main function:
|
But look at a typical main function:
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
#+BEGIN_SRC haskell
|
||||||
main w0 =
|
main w0 =
|
||||||
let (v1,w1) = action1 w0 in
|
let (v1,w1) = action1 w0 in
|
||||||
let (v2,w2) = action2 v1 w1 in
|
let (v2,w2) = action2 v1 w1 in
|
||||||
let (v3,w3) = action3 v2 w2 in
|
let (v3,w3) = action3 v2 w2 in
|
||||||
action4 v3 w3
|
action4 v3 w3
|
||||||
#+END_EXAMPLE
|
#+END_SRC
|
||||||
|
|
||||||
We have a lot of temporary elements (here =w1=, =w2= and =w3=) which
|
We have a lot of temporary elements (here =w1=, =w2= and =w3=) which must
|
||||||
must be passed on to the next action.
|
be passed on to the next action.
|
||||||
|
|
||||||
We create a function =bind= or =(>>=)=. With =bind= we don't need
|
We create a function =bind= or ~(>>=)~.
|
||||||
temporary names anymore.
|
With =bind= we don't need temporary names anymore.
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
#+BEGIN_SRC haskell
|
||||||
main =
|
main =
|
||||||
action1 >>= action2 >>= action3 >>= action4
|
action1 >>= action2 >>= action3 >>= action4
|
||||||
#+END_EXAMPLE
|
#+END_SRC
|
||||||
|
|
||||||
Bonus: Haskell has syntactical sugar for us:
|
Bonus: Haskell has syntactical sugar for us:
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
#+BEGIN_SRC haskell
|
||||||
main = do
|
main = do
|
||||||
v1 <- action1
|
v1 <- action1
|
||||||
v2 <- action2 v1
|
v2 <- action2 v1
|
||||||
v3 <- action3 v2
|
v3 <- action3 v2
|
||||||
action4 v3
|
action4 v3
|
||||||
#+END_EXAMPLE
|
#+END_SRC
|
||||||
#+END_QUOTE
|
#+END_QUOTE
|
||||||
|
|
||||||
Why did we use this strange syntax, and what exactly is this =IO= type?
|
Why did we use this strange syntax, and what exactly is this =IO= type?
|
||||||
|
@ -2542,7 +2570,7 @@ focus on the impure parts:
|
||||||
askUser = do
|
askUser = do
|
||||||
putStrLn "Enter a list of numbers (separated by commas):"
|
putStrLn "Enter a list of numbers (separated by commas):"
|
||||||
input <- getLine
|
input <- getLine
|
||||||
let maybeList = getListFromString input in
|
let maybeList = getListFromString input
|
||||||
case maybeList of
|
case maybeList of
|
||||||
Just l -> return l
|
Just l -> return l
|
||||||
Nothing -> askUser
|
Nothing -> askUser
|
||||||
|
@ -2712,7 +2740,7 @@ For example, we could also have:
|
||||||
With, of course: =actionN w :: (World) -> (a,World)=.
|
With, of course: =actionN w :: (World) -> (a,World)=.
|
||||||
|
|
||||||
#+BEGIN_QUOTE
|
#+BEGIN_QUOTE
|
||||||
IMPORTANT: there are only two important patterns to consider:
|
*IMPORTANT*: there are only two important patterns to consider:
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+BEGIN_SRC haskell
|
||||||
let (x,w1) = action1 w0 in
|
let (x,w1) = action1 w0 in
|
||||||
|
@ -2727,8 +2755,8 @@ With, of course: =actionN w :: (World) -> (a,World)=.
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
#+END_QUOTE
|
#+END_QUOTE
|
||||||
|
|
||||||
#+CAPTION: Jocker pencil trick
|
#+CAPTION: Slave Market with the disappearing bust of Voltaire
|
||||||
[[./jocker_pencil_trick.jpg]]
|
[[./slave-market-with-the-disappearing-bust-of-voltaire.jpg]]
|
||||||
|
|
||||||
Now, we will do a magic trick.
|
Now, we will do a magic trick.
|
||||||
We will make the temporary world symbols "disappear".
|
We will make the temporary world symbols "disappear".
|
||||||
|
@ -3612,10 +3640,37 @@ Thank you man.
|
||||||
shouldn't see such use in a real application except maybe for
|
shouldn't see such use in a real application except maybe for
|
||||||
debugging purposes.
|
debugging purposes.
|
||||||
|
|
||||||
[fn:6] For the curious ones, the real type is
|
[fn:6] For the curious ones, the real type looks like
|
||||||
=data IO a = IO {unIO :: State# RealWorld -> (# State# RealWorld, a #)}=.
|
=data IO a = IO {unIO :: State# RealWorld -> (# State# RealWorld, a #)}=.
|
||||||
All the =#= has to do with optimisation and I swapped the fields
|
All the =#= has to do with optimisation.
|
||||||
in my example. But this is the basic idea.
|
I swapped the fields in my example.
|
||||||
|
But this is the basic idea.
|
||||||
|
As of today, the definition of =IO= is no more visible into =base=.
|
||||||
|
We have the following explanation in [[http://hackage.haskell.org/package/base-4.12.0.0/docs/src/GHC.IO.html][=GHC.IO.hs=]]:
|
||||||
|
#+begin_quote
|
||||||
|
#+begin_src
|
||||||
|
The IO Monad is just an instance of the ST monad, where the state is
|
||||||
|
the real world. We use the exception mechanism (in GHC.Exception) to
|
||||||
|
implement IO exceptions.
|
||||||
|
|
||||||
|
NOTE: The IO representation is deeply wired in to various parts of the
|
||||||
|
system. The following list may or may not be exhaustive:
|
||||||
|
|
||||||
|
Compiler - types of various primitives in PrimOp.hs
|
||||||
|
|
||||||
|
RTS - forceIO (StgStartup.cmm)
|
||||||
|
- catchzh_fast, (un)?blockAsyncExceptionszh_fast, raisezh_fast
|
||||||
|
(Exception.cmm)
|
||||||
|
- raiseAsync (RaiseAsync.c)
|
||||||
|
|
||||||
|
Prelude - GHC.IO.hs, and several other places including
|
||||||
|
GHC.Exception.hs.
|
||||||
|
|
||||||
|
Libraries - parts of hslibs/lang.
|
||||||
|
|
||||||
|
--SDM
|
||||||
|
#+end_src
|
||||||
|
#+end_quote
|
||||||
|
|
||||||
[fn:7] Well, you'll certainly need to practice a bit to get used to them
|
[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
|
and to understand when you can use them and create your own. But
|
||||||
|
|
19
src/posts/0010-Haskell-Now/io_sum_ask.hs
Normal file
19
src/posts/0010-Haskell-Now/io_sum_ask.hs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import Data.Maybe
|
||||||
|
import Text.Read (readMaybe)
|
||||||
|
|
||||||
|
getListFromString :: String -> Maybe [Integer]
|
||||||
|
getListFromString str = readMaybe $ "[" ++ str ++ "]"
|
||||||
|
|
||||||
|
askUser :: IO [Integer]
|
||||||
|
askUser = do
|
||||||
|
putStrLn "Enter a list of numbers (separated by comma):"
|
||||||
|
input <- getLine
|
||||||
|
let maybeList = getListFromString input
|
||||||
|
case maybeList of
|
||||||
|
Just l -> return l
|
||||||
|
Nothing -> askUser
|
||||||
|
|
||||||
|
main :: IO ()
|
||||||
|
main = do
|
||||||
|
list <- askUser
|
||||||
|
print $ sum list
|
|
@ -1,18 +1,14 @@
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
|
import Text.Read (readMaybe)
|
||||||
maybeRead :: Read a => String -> Maybe a
|
|
||||||
maybeRead s = case reads s of
|
|
||||||
[(x,"")] -> Just x
|
|
||||||
_ -> Nothing
|
|
||||||
|
|
||||||
getListFromString :: String -> Maybe [Integer]
|
getListFromString :: String -> Maybe [Integer]
|
||||||
getListFromString str = maybeRead $ "[" ++ str ++ "]"
|
getListFromString str = readMaybe $ "[" ++ str ++ "]"
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
putStrLn "Enter a list of numbers (separated by comma):"
|
putStrLn "Enter a list of numbers (separated by comma):"
|
||||||
input <- getLine
|
input <- getLine
|
||||||
let maybeList = getListFromString input in
|
let maybeList = getListFromString input
|
||||||
case maybeList of
|
case maybeList of
|
||||||
Just l -> print (sum l)
|
Just l -> print (sum l)
|
||||||
Nothing -> putStrLn "Bad format. Good Bye."
|
Nothing -> putStrLn "Bad format. Good Bye."
|
||||||
|
|
|
@ -6,6 +6,7 @@ let
|
||||||
haskellDeps = ps: with ps; [
|
haskellDeps = ps: with ps; [
|
||||||
base
|
base
|
||||||
protolude
|
protolude
|
||||||
|
containers
|
||||||
];
|
];
|
||||||
|
|
||||||
ghc = haskellPackages.ghcWithPackages haskellDeps;
|
ghc = haskellPackages.ghcWithPackages haskellDeps;
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 141 KiB |
Loading…
Reference in a new issue