wip
This commit is contained in:
parent
7784f02483
commit
cc7ee03907
7 changed files with 324 additions and 72 deletions
4
src/posts/0010-Haskell-Now/fib_lazy.hs
Normal file
4
src/posts/0010-Haskell-Now/fib_lazy.hs
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
fib :: [Integer]
|
||||||
|
fib = 1:1:zipWith (+) fib (tail fib)
|
||||||
|
|
||||||
|
main = traverse_ print (take 20 (drop 200 fib))
|
|
@ -190,6 +190,7 @@ The article contains five parts:
|
||||||
haskellDeps = ps: with ps; [
|
haskellDeps = ps: with ps; [
|
||||||
base
|
base
|
||||||
protolude
|
protolude
|
||||||
|
containers
|
||||||
];
|
];
|
||||||
|
|
||||||
ghc = haskellPackages.ghcWithPackages haskellDeps;
|
ghc = haskellPackages.ghcWithPackages haskellDeps;
|
||||||
|
@ -203,6 +204,9 @@ The article contains five parts:
|
||||||
pkgs.stdenv.mkDerivation {
|
pkgs.stdenv.mkDerivation {
|
||||||
name = "env";
|
name = "env";
|
||||||
buildInputs = nixPackages;
|
buildInputs = nixPackages;
|
||||||
|
shellHook = ''
|
||||||
|
export PS1="\n[hs:\033[1;32m\]\W\[\033[0m\]]> "
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
#+end_src
|
#+end_src
|
||||||
|
|
||||||
|
@ -1751,7 +1755,8 @@ Node 7 (Node 2 Empty (Node 4 Empty Empty)) (Node 8 Empty Empty)
|
||||||
This is an informative but quite unpleasant representation of our tree.
|
This is an informative but quite unpleasant representation of our tree.
|
||||||
|
|
||||||
I've added the =containers= package in the =shell.nix= file, it is time to
|
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.
|
use this library which contain functions to show trees and list of trees
|
||||||
|
(forest) named =drawTree= and =drawForest=.
|
||||||
|
|
||||||
#+BEGIN_SRC haskell :tangle pretty_tree.hs
|
#+BEGIN_SRC haskell :tangle pretty_tree.hs
|
||||||
import Data.Tree (Tree,Forest(..))
|
import Data.Tree (Tree,Forest(..))
|
||||||
|
@ -1814,8 +1819,6 @@ Int binary tree:
|
||||||
|
|
|
|
||||||
`- 23
|
`- 23
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Note we could also use another type
|
Note we could also use another type
|
||||||
|
|
||||||
String binary tree:
|
String binary tree:
|
||||||
|
@ -1829,11 +1832,8 @@ String binary tree:
|
||||||
|
|
|
|
||||||
`- "yog"
|
`- "yog"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
As we can test equality and order trees, we can make tree of trees!
|
As we can test equality and order trees, we can make tree of trees!
|
||||||
|
|
||||||
|
|
||||||
Binary tree of Char binary trees:
|
Binary tree of Char binary trees:
|
||||||
Node 'f' Empty (Node 'o' Empty Empty)
|
Node 'f' Empty (Node 'o' Empty Empty)
|
||||||
|
|
|
|
||||||
|
@ -1914,18 +1914,41 @@ function =take= which is equivalent to our =take'=.
|
||||||
|
|
||||||
This code is mostly the same as the previous one.
|
This code is mostly the same as the previous one.
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+begin_src haskell :tangle infinite_tree.hs :exports none
|
||||||
import Debug.Trace (trace)
|
import Data.Tree (Tree,Forest(..))
|
||||||
import Data.List
|
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)
|
deriving (Eq,Ord,Show)
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
|
||||||
|
#+begin_src haskell :tangle infinite_tree.hs :exports none
|
||||||
|
|
||||||
|
-- | 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
|
||||||
|
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
|
||||||
Suppose we don't mind having an ordered binary tree.
|
Suppose we don't mind having an ordered binary tree.
|
||||||
Here is an infinite binary tree:
|
Here is an infinite binary tree:
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+BEGIN_SRC haskell :tangle infinite_tree.hs
|
||||||
nullTree = Node 0 nullTree nullTree
|
nullTree = Node 0 nullTree nullTree
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
@ -1933,7 +1956,7 @@ A complete binary tree where each node is equal to 0.
|
||||||
Now I will prove you can manipulate this object using the following
|
Now I will prove you can manipulate this object using the following
|
||||||
function:
|
function:
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+BEGIN_SRC haskell :tangle infinite_tree.hs
|
||||||
-- take all element of a BinTree
|
-- take all element of a BinTree
|
||||||
-- up to some depth
|
-- up to some depth
|
||||||
treeTakeDepth _ Empty = Empty
|
treeTakeDepth _ Empty = Empty
|
||||||
|
@ -1947,34 +1970,83 @@ function:
|
||||||
|
|
||||||
See what occurs for this program:
|
See what occurs for this program:
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
{{{lnk(infinite_tree.hs)}}}
|
||||||
main = print $ treeTakeDepth 4 nullTree
|
#+BEGIN_SRC haskell :tangle infinite_tree.hs
|
||||||
|
main = prettyPrintTree (treeTakeDepth 4 nullTree)
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
This code compiles, runs and stops giving the following result:
|
This code compiles, runs and stops giving the following result:
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
#+BEGIN_EXAMPLE
|
||||||
< 0
|
[hs:hsenv]> runghc infinite_tree.hs
|
||||||
: |-- 0
|
0
|
||||||
: | |-- 0
|
|
|
||||||
: | | |-- 0
|
+- 0
|
||||||
: | | `-- 0
|
| |
|
||||||
: | `-- 0
|
| +- 0
|
||||||
: | |-- 0
|
| | |
|
||||||
: | `-- 0
|
| | +- 0
|
||||||
: `-- 0
|
| | |
|
||||||
: |-- 0
|
| | `- 0
|
||||||
: | |-- 0
|
| |
|
||||||
: | `-- 0
|
| `- 0
|
||||||
: `-- 0
|
| |
|
||||||
: |-- 0
|
| +- 0
|
||||||
: `-- 0
|
| |
|
||||||
|
| `- 0
|
||||||
|
|
|
||||||
|
`- 0
|
||||||
|
|
|
||||||
|
+- 0
|
||||||
|
| |
|
||||||
|
| +- 0
|
||||||
|
| |
|
||||||
|
| `- 0
|
||||||
|
|
|
||||||
|
`- 0
|
||||||
|
|
|
||||||
|
+- 0
|
||||||
|
|
|
||||||
|
`- 0
|
||||||
|
|
||||||
#+END_EXAMPLE
|
#+END_EXAMPLE
|
||||||
|
|
||||||
Just to heat up your neurones a bit more, let's make a slightly more
|
Just to heat up your neurones a bit more, let's make a slightly more
|
||||||
interesting tree:
|
interesting tree:
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
|
||||||
|
#+begin_src haskell :tangle infinite_tree_2.hs :exports none
|
||||||
|
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)
|
||||||
|
|
||||||
|
-- | 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
|
||||||
|
|
||||||
|
-- | 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
|
||||||
|
|
||||||
|
|
||||||
|
#+BEGIN_SRC haskell :tangle infinite_tree_2.hs
|
||||||
iTree = Node 0 (dec iTree) (inc iTree)
|
iTree = Node 0 (dec iTree) (inc iTree)
|
||||||
where
|
where
|
||||||
dec (Node x l r) = Node (x-1) (dec l) (dec r)
|
dec (Node x l r) = Node (x-1) (dec l) (dec r)
|
||||||
|
@ -1986,7 +2058,7 @@ This function should be similar to =map=, but should work on =BinTree=
|
||||||
instead of list.
|
instead of list.
|
||||||
Here is such a function:
|
Here is such a function:
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+BEGIN_SRC haskell :tangle infinite_tree_2.hs
|
||||||
-- apply a function to each node of Tree
|
-- apply a function to each node of Tree
|
||||||
treeMap :: (a -> b) -> BinTree a -> BinTree b
|
treeMap :: (a -> b) -> BinTree a -> BinTree b
|
||||||
treeMap f Empty = Empty
|
treeMap f Empty = Empty
|
||||||
|
@ -2001,7 +2073,7 @@ structures, search for functor and =fmap=.
|
||||||
|
|
||||||
Our definition is now:
|
Our definition is now:
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+BEGIN_SRC haskell :tangle infinite_tree_2.hs
|
||||||
infTreeTwo :: BinTree Int
|
infTreeTwo :: BinTree Int
|
||||||
infTreeTwo = Node 0 (treeMap (\x -> x-1) infTreeTwo)
|
infTreeTwo = Node 0 (treeMap (\x -> x-1) infTreeTwo)
|
||||||
(treeMap (\x -> x+1) infTreeTwo)
|
(treeMap (\x -> x+1) infTreeTwo)
|
||||||
|
@ -2009,33 +2081,102 @@ Our definition is now:
|
||||||
|
|
||||||
Look at the result for
|
Look at the result for
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
{{{lnk(infinite_tree_2.hs)}}}
|
||||||
main = print $ treeTakeDepth 4 infTreeTwo
|
#+BEGIN_SRC haskell :tangle infinite_tree_2.hs
|
||||||
|
main = prettyPrintTree $ treeTakeDepth 4 infTreeTwo
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
#+BEGIN_EXAMPLE
|
||||||
< 0
|
[hs:hsenv]> runghc infinite_tree_2.hs
|
||||||
: |-- -1
|
0
|
||||||
: | |-- -2
|
|
|
||||||
: | | |-- -3
|
+- -1
|
||||||
: | | `-- -1
|
| |
|
||||||
: | `-- 0
|
| +- -2
|
||||||
: | |-- -1
|
| | |
|
||||||
: | `-- 1
|
| | +- -3
|
||||||
: `-- 1
|
| | |
|
||||||
: |-- 0
|
| | `- -1
|
||||||
: | |-- -1
|
| |
|
||||||
: | `-- 1
|
| `- 0
|
||||||
: `-- 2
|
| |
|
||||||
: |-- 1
|
| +- -1
|
||||||
: `-- 3
|
| |
|
||||||
|
| `- 1
|
||||||
|
|
|
||||||
|
`- 1
|
||||||
|
|
|
||||||
|
+- 0
|
||||||
|
| |
|
||||||
|
| +- -1
|
||||||
|
| |
|
||||||
|
| `- 1
|
||||||
|
|
|
||||||
|
`- 2
|
||||||
|
|
|
||||||
|
+- 1
|
||||||
|
|
|
||||||
|
`- 3
|
||||||
#+END_EXAMPLE
|
#+END_EXAMPLE
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+begin_notes
|
||||||
main = do
|
The important things to remember.
|
||||||
print $ treeTakeDepth 4 nullTree
|
Haskell handle infinite structures naturally mostly because it is not strict.
|
||||||
print $ treeTakeDepth 4 infTreeTwo
|
|
||||||
#+END_SRC
|
So you can write, infinite tree, but also, you can generate infinite list
|
||||||
|
like this common example:
|
||||||
|
|
||||||
|
#+begin_src haskell :tangle fib_lazy.hs
|
||||||
|
fib :: [Integer]
|
||||||
|
fib = 1:1:zipWith (+) fib (tail fib)
|
||||||
|
|
||||||
|
main = traverse_ print (take 20 (drop 200 fib))
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
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
|
||||||
|
- =(!!)= is used to get the nth element of a list.
|
||||||
|
- =drop n= remove n element 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
|
||||||
|
=[op a1 b1,op a2 b2,op a3 b3, .... ]=
|
||||||
|
- =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.
|
||||||
|
Because, =fib= is a list that will be used as "cache" to compute each
|
||||||
|
number even considering the code looks a bit like a double recursion.
|
||||||
|
|
||||||
|
#+begin_example
|
||||||
|
[hs:0010-Haskell-Now]> time runghc fib_lazy.hs
|
||||||
|
453973694165307953197296969697410619233826
|
||||||
|
734544867157818093234908902110449296423351
|
||||||
|
1188518561323126046432205871807859915657177
|
||||||
|
1923063428480944139667114773918309212080528
|
||||||
|
3111581989804070186099320645726169127737705
|
||||||
|
5034645418285014325766435419644478339818233
|
||||||
|
8146227408089084511865756065370647467555938
|
||||||
|
13180872826374098837632191485015125807374171
|
||||||
|
21327100234463183349497947550385773274930109
|
||||||
|
34507973060837282187130139035400899082304280
|
||||||
|
55835073295300465536628086585786672357234389
|
||||||
|
90343046356137747723758225621187571439538669
|
||||||
|
146178119651438213260386312206974243796773058
|
||||||
|
236521166007575960984144537828161815236311727
|
||||||
|
382699285659014174244530850035136059033084785
|
||||||
|
619220451666590135228675387863297874269396512
|
||||||
|
1001919737325604309473206237898433933302481297
|
||||||
|
1621140188992194444701881625761731807571877809
|
||||||
|
2623059926317798754175087863660165740874359106
|
||||||
|
4244200115309993198876969489421897548446236915
|
||||||
|
|
||||||
|
real 0m1.000s
|
||||||
|
user 0m0.192s
|
||||||
|
sys 0m0.058s
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
#+end_notes
|
||||||
|
|
||||||
* Difficulty: Hard
|
* Difficulty: Hard
|
||||||
:PROPERTIES:
|
:PROPERTIES:
|
||||||
|
@ -2043,7 +2184,7 @@ Look at the result for
|
||||||
:END:
|
:END:
|
||||||
|
|
||||||
Congratulations for getting so far!
|
Congratulations for getting so far!
|
||||||
Now, some of the really hardcore stuff can start.
|
Now, some of the really hard stuff can start.
|
||||||
|
|
||||||
If you are like me, you should get the functional style.
|
If you are like me, you should get the functional style.
|
||||||
You should also understand a bit more the advantages of laziness by
|
You should also understand a bit more the advantages of laziness by
|
||||||
|
@ -2067,7 +2208,7 @@ But they are all very rewarding.
|
||||||
[[./magritte_carte_blanche.jpg]]
|
[[./magritte_carte_blanche.jpg]]
|
||||||
|
|
||||||
#+BEGIN_QUOTE
|
#+BEGIN_QUOTE
|
||||||
tldr;
|
{{{tldr}}}
|
||||||
|
|
||||||
A typical function doing =IO= looks a lot like an imperative program:
|
A typical function doing =IO= looks a lot like an imperative program:
|
||||||
|
|
||||||
|
@ -2083,11 +2224,14 @@ But they are all very rewarding.
|
||||||
- To set a value to an object we use =<-= .
|
- To set a value to an object we use =<-= .
|
||||||
- The type of each line is =IO *=; in this example:
|
- The type of each line is =IO *=; in this example:
|
||||||
|
|
||||||
- =action1 :: IO b=
|
#+begin_src haskell
|
||||||
- =action2 x :: IO ()=
|
- action1 :: IO b
|
||||||
- =action3 :: IO c=
|
- x :: b
|
||||||
- =action4 x y :: IO a=
|
- action2 x :: IO ()
|
||||||
- =x :: b=, =y :: c=
|
- action3 :: IO c
|
||||||
|
- y :: c
|
||||||
|
- action4 x y :: IO a
|
||||||
|
#+end_src
|
||||||
|
|
||||||
- Few objects have the type =IO a=, this should help you choose. In
|
- Few objects have the type =IO a=, this should help you choose. In
|
||||||
particular you cannot use pure functions directly here. To use pure
|
particular you cannot use pure functions directly here. To use pure
|
||||||
|
@ -2108,7 +2252,8 @@ Ask a user to enter a list of numbers.
|
||||||
Print the sum of the numbers.
|
Print the sum of the numbers.
|
||||||
#+END_QUOTE
|
#+END_QUOTE
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
{{{lnk(io_sum.hs)}}}
|
||||||
|
#+BEGIN_SRC haskell :tangle io_sum.hs
|
||||||
toList :: String -> [Integer]
|
toList :: String -> [Integer]
|
||||||
toList input = read ("[" ++ input ++ "]")
|
toList input = read ("[" ++ input ++ "]")
|
||||||
|
|
||||||
|
@ -2172,7 +2317,7 @@ For example, what happens if the user enters something strange?
|
||||||
Let's try:
|
Let's try:
|
||||||
|
|
||||||
#+BEGIN_EXAMPLE
|
#+BEGIN_EXAMPLE
|
||||||
% runghc 02_progressive_io_example.lhs
|
[hs:hsenv]> runghc io_sum.hs
|
||||||
Enter a list of numbers (separated by comma):
|
Enter a list of numbers (separated by comma):
|
||||||
foo
|
foo
|
||||||
Prelude.read: no parse
|
Prelude.read: no parse
|
||||||
|
@ -2187,7 +2332,7 @@ In order to do this, we must detect that something went wrong.
|
||||||
Here is one way to do this: use the type =Maybe=.
|
Here is one way to do this: use the type =Maybe=.
|
||||||
This is a very common type in Haskell.
|
This is a very common type in Haskell.
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+BEGIN_SRC haskell :tangle io_sum_safe.hs
|
||||||
import Data.Maybe
|
import Data.Maybe
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
|
@ -2208,7 +2353,7 @@ If the value is right, it returns =Just <the value>=.
|
||||||
Don't try to understand too much of this function.
|
Don't try to understand too much of this function.
|
||||||
I use a lower level function than =read=: =reads=.
|
I use a lower level function than =read=: =reads=.
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+BEGIN_SRC haskell :tangle io_sum_safe.hs
|
||||||
maybeRead :: Read a => String -> Maybe a
|
maybeRead :: Read a => String -> Maybe a
|
||||||
maybeRead s = case reads s of
|
maybeRead s = case reads s of
|
||||||
[(x,"")] -> Just x
|
[(x,"")] -> Just x
|
||||||
|
@ -2219,14 +2364,14 @@ 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=.
|
||||||
Otherwise, for example for "1,2,3", it will return =Just [1,2,3]=.
|
Otherwise, for example for "1,2,3", it will return =Just [1,2,3]=.
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+BEGIN_SRC haskell :tangle io_sum_safe.hs
|
||||||
getListFromString :: String -> Maybe [Integer]
|
getListFromString :: String -> Maybe [Integer]
|
||||||
getListFromString str = maybeRead $ "[" ++ str ++ "]"
|
getListFromString str = maybeRead $ "[" ++ 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.
|
||||||
|
|
||||||
#+BEGIN_SRC haskell
|
#+BEGIN_SRC haskell :tangle io_sum_safe.hs
|
||||||
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):"
|
||||||
|
@ -2234,15 +2379,13 @@ We simply have to test the value in our main function.
|
||||||
let maybeList = getListFromString input in
|
let maybeList = getListFromString input in
|
||||||
case maybeList of
|
case maybeList of
|
||||||
Just l -> print (sum l)
|
Just l -> print (sum l)
|
||||||
Nothing -> error "Bad format. Good Bye."
|
Nothing -> putStrLn "Bad format. Good Bye."
|
||||||
#+END_SRC
|
#+END_SRC
|
||||||
|
|
||||||
In case of error, we display a nice error message.
|
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
|
Note that the type of each expression in the main's =do= block remains of
|
||||||
the form =IO a=.
|
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
|
One very important thing to note is the type of all the functions defined
|
||||||
so far.
|
so far.
|
||||||
|
|
32
src/posts/0010-Haskell-Now/infinite_tree.hs
Normal file
32
src/posts/0010-Haskell-Now/infinite_tree.hs
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
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)
|
||||||
|
|
||||||
|
-- | 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
|
||||||
|
|
||||||
|
nullTree = Node 0 nullTree nullTree
|
||||||
|
|
||||||
|
-- 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
|
||||||
|
|
||||||
|
main = prettyPrintTree (treeTakeDepth 4 nullTree)
|
45
src/posts/0010-Haskell-Now/infinite_tree_2.hs
Normal file
45
src/posts/0010-Haskell-Now/infinite_tree_2.hs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
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)
|
||||||
|
|
||||||
|
-- | 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
|
||||||
|
|
||||||
|
-- | 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
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
-- 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)
|
||||||
|
|
||||||
|
infTreeTwo :: BinTree Int
|
||||||
|
infTreeTwo = Node 0 (treeMap (\x -> x-1) infTreeTwo)
|
||||||
|
(treeMap (\x -> x+1) infTreeTwo)
|
||||||
|
|
||||||
|
main = prettyPrintTree $ treeTakeDepth 4 infTreeTwo
|
7
src/posts/0010-Haskell-Now/io_sum.hs
Normal file
7
src/posts/0010-Haskell-Now/io_sum.hs
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
toList :: String -> [Integer]
|
||||||
|
toList input = read ("[" ++ input ++ "]")
|
||||||
|
|
||||||
|
main = do
|
||||||
|
putStrLn "Enter a list of numbers (separated by comma):"
|
||||||
|
input <- getLine
|
||||||
|
print $ sum (toList input)
|
18
src/posts/0010-Haskell-Now/io_sum_safe.hs
Normal file
18
src/posts/0010-Haskell-Now/io_sum_safe.hs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
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 ++ "]"
|
||||||
|
|
||||||
|
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 -> putStrLn "Bad format. Good Bye."
|
|
@ -19,4 +19,7 @@ in
|
||||||
pkgs.stdenv.mkDerivation {
|
pkgs.stdenv.mkDerivation {
|
||||||
name = "env";
|
name = "env";
|
||||||
buildInputs = nixPackages;
|
buildInputs = nixPackages;
|
||||||
|
shellHook = ''
|
||||||
|
export PS1="\n[hs:\033[1;32m\]\W\[\033[0m\]]> "
|
||||||
|
'';
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue