Simple update

This commit is contained in:
Yann Esposito (Yogsototh) 2018-06-21 22:02:57 +02:00
parent 44e1b7805c
commit bc108b581f
Signed by untrusted user who does not match committer: yogsototh
GPG key ID: 7B19A4C650D59646
4 changed files with 142 additions and 164 deletions

View file

@ -107,7 +107,7 @@ This book is very opinionated, because I wanted to be efficient in learning
fast for some specific kind of personalities.
It might not be for you.
One of my goal is to shortcicuit some classic learning detour.
One of my goal is to shortcircuit some classic learning detour.
For a lot of decisions I generally make only one choice. I'll try to talk about
the other choices and it will be your duty to explore other choices after you

View file

@ -62,62 +62,7 @@ curl -sSL https://get.haskellstack.org/ | sh
*** TO-CLEAN git
You should have [[https://git-scm.com][=git=]] installed.
*** TO-CLEAN Stack template
Before starting to write your first line of code.
Let's create a project with a sane and modern file organisation.
I made a stack templates largely inspired by tasty-travis template. It will
provide a bootstrap for organizing your application with tests, benchmarks and
continuous integration.
This template provide a file organisation for your projects.
Mainly do jump into programmin you could theoretically just download the binary
of the main Haskell compiler GHC to your compiler and compile each file with
=ghc myfile.hs=. But let's face it. It's not suitable for real project which
need more informations about it.
So let's start with a sane professional organisation for your files.
#+BEGIN_SRC shell
stack new myproject https://git.io/vbpej
#+END_SRC
After that, this should generate a new `myproject` directory with the following
files:
#+BEGIN_SRC
> tree
.
├── CHANGELOG.md
├── LICENSE
├── README.md
├── Setup.hs
├── myproject.cabal
├── package.yaml
├── src
│ └── Lib.hs
├── src-benchmark
│ └── Main.hs
├── src-doctest
│ └── Main.hs
├── src-exe
│ └── Main.hs
├── src-test
│ └── Main.hs
├── stack.yaml
└── tutorial.md
5 directories, 13 files
#+END_SRC
Most of your source code should be in the =src= directory. Generally =src-exe=
should be a minimal code that could handle the =main= function to start your
application. We'll talk about other part later in the book but most other file
should be quite straightforward.
You should have =[[https://git-scm.com][git]]= installed.
*** TO-CLEAN Editor
@ -173,7 +118,6 @@ I think you can change the value of =dotspacemacs-editing-style= from ='vim=
to ='hybrid= or ='emacs= in the =.spacemacs= file.
It should be good now.
*** TO-CLEAN Conclusion
First you can congratulate yourself to have installed all the prerequiste to

View file

@ -151,14 +151,37 @@ main = do
putText ("Hello " <> name <> "!")
#+END_SRC
We can try that in the REPL (GHCI). You shold be able to start it from your
We can try that in the REPL (GHCI). You should be able to start it from your
editor. For example in spacemacs I can load the current buffer (open file) in
the REPL with =SPC m s b=.
You could also start the repl in a terminal with =stack ghci=
And then load the module with =:l src-exe/Main=.
And then load the module with =:l hello_name.hs=.
The =:l= is a shortcut for =:load=.
#+BEGIN_SRC
> stack ghci
Warning: No local targets specified, so ghci will not use any options from your package.yaml / *.cabal files.
Potential ways to resolve this:
* If you want to use the package.yaml / *.cabal package in the current directory, use stack init to create a new stack.yaml.
* Add to the 'packages' field of ~/.stack/global-project/stack.yaml
Configuring GHCi with the following packages:
GHCi, version 8.2.2: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /private/var/folders/bp/_8thkcjd4k3g81mpxtkq44h80000gn/T/ghci70782/ghci-script
Prelude> :l hello_name.hs
[1 of 1] Compiling Main ( hello_name.hs, interpreted ) [flags changed]
Ok, one module loaded.
*Main> main
What is your name?
Yann
Hello Yann!
#+END_SRC
But you should also simply run it from command line:
#+BEGIN_SRC
> ./hello_name.sh
What is your name?
@ -310,13 +333,13 @@ Here are all the possible choices:
That is already 5 different choices. But there is another package that provide other string choices.
In =Foundation= the strings are =UTF-8=.
Mmmm so much choices.
Hmmm... so much choices.
So to make it clear, in general, don't use =String= for anything serious.
Use =Text= most of the time.
A rule of thumbs is to never use =String= for anything serious.
Use =Text= most of the time because they support encoding.
Use =Bytestring= if you need efficient bytes arrays.
By using Protolude, we prevent the use of =String= naturally.
By using Protolude, we naturally don't use =String=.
**** TO-CLEAN Write a guess my age program
@ -328,9 +351,18 @@ The =src-exe/Main.hs= should be very minimalist, so now let's change its content
by:
#+BEGIN_SRC haskell
#!/usr/bin/env stack
{- stack script
--resolver lts-11.6
--install-ghc
--package protolude
-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
import Protolude
import Guess (guess)
guess :: IO ()
guess = undefined
main :: IO ()
main = do
@ -338,28 +370,23 @@ main = do
putText "Thanks for playing!"
#+END_SRC
Now we need to create the file =src/Guess.hs= which should declare the function
=guess=. Let's start with this content:
#+BEGIN_SRC haskell
module Guess
( guess
) where
import Protolude
guess :: IO ()
guess = undefined
#+END_SRC
We declare a =Guess= module which use Protolude.
We know that the type of guess must be =IO ()=.
We don't know yet what the code will be so I just used =undefined=.
This way the program will be able to typecheck.
So here is the program that will try to guess your age:
The next step is to define the ~guess~ function.
#+BEGIN_SRC haskell :tangle code/guess-1.hs
#!/usr/bin/env stack
{- stack script
--resolver lts-11.6
--install-ghc
--package protolude
-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
import Protolude
#+BEGIN_SRC haskell
guess :: IO ()
guess = guessBetween 0 120
@ -374,6 +401,11 @@ guessBetween minAge maxAge = do
case answer of
"y" -> guessBetween minAge (age - 1)
_ -> guessBetween (if age == minAge then age + 1 else age) maxAge
main :: IO ()
main = do
guess
putText "Thanks for playing!"
#+END_SRC
So going from there we declared the =guess= function to call the =guessBetween=
@ -625,16 +657,67 @@ For that we will use the =optparse-generic= package.
*** TODO File Access
*** TODO Daemons & Logging
** TODO Intermediate
*** TO-CLEAN Init the project
*** TO-CLEAN Stack template
☞ As a first projet a lot of new concept will be introduced. Don't be
discouraged by that.
#+BEGIN_SRC
> stack new guess https://git.io/vbpej
> cd guess
Let's create a project with a sane and modern file organisation.
I made a stack templates largely inspired by =tasty-travis= template. It will
provide a bootstrap for organizing your application with tests, benchmarks and
continuous integration.
This template provide a file organisation for your projects.
Mainly do jump into programmin you could theoretically just download the binary
of the main Haskell compiler GHC to your compiler and compile each file with
=ghc myfile.hs=. But let's face it. It's not suitable for real project which
need more informations about it.
So let's start with a sane professional organisation for your files.
#+BEGIN_COMMENT
****** TODO modify the URL to use a better URL: torrent / IPFS
#+END_COMMENT
#+BEGIN_SRC shell
stack new guess https://git.io/vbpej
#+END_SRC
After that, this should generate a new ~guess~ directory with the following
files:
#+BEGIN_SRC
> tree
.
├── CHANGELOG.md
├── LICENSE
├── README.md
├── Setup.hs
├── guess.cabal
├── package.yaml
├── src
│ └── Lib.hs
├── src-benchmark
│ └── Main.hs
├── src-doctest
│ └── Main.hs
├── src-exe
│ └── Main.hs
├── src-test
│ └── Main.hs
├── stack.yaml
└── tutorial.md
5 directories, 13 files
#+END_SRC
Most of your source code should be in the =src= directory. Generally =src-exe=
should be a minimal code that could handle the =main= function to start your
application. We'll talk about other parts later in the book but most other file
should be quite straightforward.
Edit the file =src-exe/Main.hs=
The file contains:
@ -658,84 +741,6 @@ To compile it do a
So that program print 42 and stop.
Let's go line by line about what is occuring here.
- =import Protolude=: Haskell is a language, but you need to start with some
useful definition for you. And Protolude is a /prelude/. That mean that it
provides a list of useful definitions for you. By default you don't need to
import manually the default prelude. But the more you work with Haskell the
more you feel the need to write your own prelude. =Protolude= is a sane
minimal and professional starting point.
- =import Lib (inc)=: That line means that we import the function =inc= from
another module named =Lib= The module correspond to the file =src/Lib.hs=. No
need to look into it now.
- =main :: IO ()=:
This is the declaration of the type of the =main= function.
The main function will be the function called when you launch your
application. Excatly like in =C=. The type is =IO ()=. It means that
=main= will make some interaction with the system and will return
nothing.
- =main = print . inc $ (41 :: Int)=
For that line there are in fact a lot of things going on.
We define the function =main=.
Lets compare this notation with other programming languages:
C:
#+BEGIN_SRC c
void main () {
...
}
#+END_SRC
javascript:
#+BEGIN_SRC javascript
function main() {
...
}
#+END_SRC
python:
#+BEGIN_SRC python
def main:
...
#+END_SRC
LISP:
#+BEGIN_SRC elisp
(define foo () ...)
#+END_SRC
Clojure:
#+BEGIN_SRC clojure
(defn main [] ...)
#+END_SRC
Now take a look at the content:
#+BEGIN_SRC haskell
main = print (inc 41)
#+END_SRC
☞ A very important syntax detail;
function application is done with a simple space.
So =foo bar= means you apply the function =foo= to the parameter =bar=.
And by default the priority is on the left.
So: =foo bar baz= is equivalent to =(foo bar) baz=.
While that notation is quite simpler it can take some time to be used to it and
to parse it naturally.
So here we first call =inc= on =41= wich is =42=.
Then we print it to the standard output.
And that's it.
*** TODO DB Access
**** NoSQL (Redis looks easy)
**** Stream DB (Kafka or NATS, etc...)

29
code/guess-1.hs Executable file
View file

@ -0,0 +1,29 @@
#!/usr/bin/env stack
{- stack script
--resolver lts-11.6
--install-ghc
--package protolude
-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
import Protolude
guess :: IO ()
guess = guessBetween 0 120
guessBetween :: Integer -> Integer -> IO ()
guessBetween minAge maxAge = do
let age = (maxAge + minAge) `div` 2
if minAge == maxAge
then putText ("You are " <> show minAge)
else do
putText ("Are you younger than " <> show age <> "?")
answer <- getLine
case answer of
"y" -> guessBetween minAge (age - 1)
_ -> guessBetween (if age == minAge then age + 1 else age) maxAge
main :: IO ()
main = do
guess
putText "Thanks for playing!"