deft/HWP.org

400 lines
12 KiB
Org Mode
Raw Normal View History

2017-12-30 23:07:49 +00:00
#+TITLE: Haskell for the working programmer
#+AUTHOR: Yann Esposito
#+EMAIL: yann.esposito@gmail.com
#+LANGUAGE: en
/THIS IS A WORK IN PROGRESS/
#+TOC: headlines
* TODO Introduction
This is somehow a follow-up from Learn Haskell Fast and Hard.
Which was more about being able to /play/ with Haskell than to /work/ with it.
This book is aimed to be one of the fastest way to learn how to be productive
with Haskell.
Know that there still will be a very long road ahead once this book will be
finished to master Haskell. That should be ok.
Modern computing has unfortunately less to do with algorithmic than to create a
mashup of libs and external APIs.
So while learning all the details of Haskell can seems like an impossible challenge.
Learning the necessary skills to be productive shouldn't be that hard.
What does this book will talk about.
1. Having a clean and stable dev environment
2. Basic Introduction to the language
3. Professional Project developement workflow
4. Make command line program
5. Use external libraries
6. Handle the filesystem
7. Handle a few DBs
8. Make a basic REST API
** What does "working programmer" stand for?
Being able to:
- create a new working program from scratch,
- work with the filesystem (read/write files/directories),
- work with BDD (SQLite, PostgresSQL, MongoDB, etc...),
- work with network (send/receive HTTP request),
- make a REST API,
- write test for your application,
- to deploy your application
This is more about being an user, consumer from the Haskell community than being
an active contributor. Hopefully the gap won't be hard to pass from user to
contributor. So I'll write a minimal chapter about how to write your own library
and publish it for other developpers.
** Prerequiste
The target audience I'm writting this book for is software developpers.
You should:
- be familiar with some programming language,
- be familiar with command line in a shell,
- know how to editing text files (I try to focus on generic editors like emacs, vim, etc...),
- know the basic usage of =git=
If you don't know that, your journey with this book might be a bit difficult but
I'll do my best to not make it impossible.
** Opinionated
Keep in mind that Haskell has a very active and open ecosystem.
And the language itself let you make very different choices to the fundamentals.
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.
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
completed this book to decide which is the one that has your preference.
Also note that this book was written in the past. And as I said Haskell
ecosystem evolve very fast. And some choices which are an evidence today might
be deprecated in a few months from now.
Typically there are many different and concurrent web frameworks, db libs, etc..
** TODO A Word about Haskell philosophy
One Haskell main characteristic is that it tends to make the right/most secure
choice by default.
A very simple example is that it is generally harder to write unsafe code than
to write safe and pure code.
Also one of the reason I think Haskell is percieved as hard to learn by many
people is that you generally need to ingest a lot of concepts before being able
to be productive.
** Install a dev environment (about 30 minutes)
*** Working environment
A thing to note is the distinction between learning a language for personal
interrest for some personal project and learning with the goal to achieve a
"product" with some hard time to deliver.
So for example, it can be nice to understand the language by playing inside a
REPL. That will be very almost not used in this book as the goal is not to
really gain a deeper knowledge but perhaps to be able to "use" the language.
The problem I try to solve in this book is to make you an "user" of Haskell more
than a "contributor" to Haskell. While I encourage everybody to gain deeper
understanding on the internals of Haskell.
*** Stack
I recommend [[https://haskellstack.org][stack]]. But there are many different method to install Haskell.
Stack should be simple and efficient.
If thing haven't changed sint the book is written it could be installed with:
#+BEGIN_SRC shell
curl -sSL https://get.haskellstack.org/ | sh
#+END_SRC
*** git
You should have [[https://git-scm.com][=git=]] installed.
*** Stack template tasty-travis
There are different level of organisations for in a program.
- file organsation
- internal function / data / namespace organisations
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 tasty-travis my-project
#+END_SRC
*** Editor
I recommend spacemacs with the haskell layer because it comes with battery included.
On the other hand you can use any editor you like.
Just don't lose too much time trying to configure intero or ghc-mod.
I wouldn't recommend you to use full featured IDE like Visual Studio, Eclipse, etc...
Why?
One of the best part of Haskell is the tooling around the language.
And typically, =intero= is really great to use.
You'll see errors, warn and hints while you're typing your code.
It is also useful to have hoogle and hayoo, which are search engine focused on Haskell.
* TODO Working like in any other language
** TODO The syntax
Let's put that behind us ASAP.
Syntax is really the thing most people focus about when learning a new
programming language.
With more experience, I find that its most of the time totally irrelevant.
And the real interrest of a new programming language isn't about the syntax.
Otherwise all programming languages would look either like LISP or Ruby.
*** TODO Copy from my article Learn Haskell Fast & Hard
- Basic: spaces are meaningful like in Python.
- Variables are like math variables. They are immutables.
- Function definition, lack of parenthesis is one of the thing that make it the
most specific and hard to adapt.
=f x y = x=
This is why I'll try to use more parenthesis than in "real world code".
- Functions are first class (can be parameters like any other variables).
- Curring can also be surprising but you should understand that as the ability
to reach a higher level of abstraction.
*** *VERY IMPORTANT PART!* Typing Notation
So that will be VERY VERY IMPORTANT to be able to work with Haskell efficiently.
One of the central Haskell property is to try to help you, the developer, to
write checks and constraints on your code while you write it.
That way of writing code take some time to really be used to.
So here we go:
**** Basic Types
A type is a way of "labelling" an expression by providing some constraint on it.
The most basic types are the types you might certainly be used to.
- =Bool=: this type has only two possible values; =True= and =False=.
- =Char=: a 8 bits char
- Numbers (There are many of them)
- =Int= (classical integer with min and max depending on your machine properties)
- =Integer= (unbounded integer representation)
- =Float= (single precision floating point)
- =Double= (double precision floating point)
There is also another interresting type: Unit that is denoted =()=.
=Bool= is inhabited by =True= and =False=, =()= is inhabited only by the /value/ =()=.
It is a bit difficult but =()= denote at the same time a type when it is written
in a context where we deal with types and as a value when the context make it
clear we wait a value.
When you read Haskell code some part are about types and others are about values.
#+BEGIN_SRC haskell
foo :: Int -- after the :: these are types
foo = 42 -- this is about values
#+END_SRC
**** Type Composition
One interresting thing to think about is that for each value we associate a type.
But types themselves are categorized. And we use /kind/ for that.
#+BEGIN_QUOTE
A /kind/ is to a type what a type is to a value.
#+END_QUOTE
So all basic types are of kind =*=.
#+BEGIN_SRC
> stack ghci
...
Prelude> :t 'a'
'a' :: Char
Prelude> :k Char
Char :: *
#+END_SRC
Now you should imagine where this is going.
Like functions, types can take another types as variables.
So types can compose.
Basic types that help composes:
- list: =[] :: * -> *=
- =[Char] :: *=
- =[Int] :: *=
- tuples: =(,) :: * -> * -> *=
- =(,) Char :: * -> *=
- =(Char,Int) :: *=
One very important thing to note is that that functions can only be from type of kind * to type of kind *.
- function: =(->) :: TYPE q -> TYPE r -> *=
**** Custom Data Type / Records
So now:
#+BEGIN_SRC haskell
type Foo = Bool -- type synonym
data Bar = BarConstr Int Char
-- Bar is the type
-- BarConstr is the type construction, it's a function of type: Int -> Char -> Bar
-- :kind Bar :: *
-- :kind BarConstr <-- ERROR, this is not a type
data Baz a = BazConstr Char a
-- :kind Baz :: * -> *
-- :kind BazConstr <-- ERROR, a constructor is not a type
#+END_SRC
** TODO IO
If you know another popular programming language you probably aren't aware that
you code "in" =IO=. What I mean by that is that you can write a print statement
anywhere in your code and it will be executed when the program evaluate that
line. This is generally the first method used in debugging or during development
to understand what's going on.
So Haskell is slightly different in this regard.
In Haskell there are places where you'll be able to add the same kind of print statements.
But in some other places, it will be forbidden.
Example:
#+BEGIN_SRC haskell
pureadd x y = x + y
ioAdd x y = do
print x
print y
print (x+y)
return (x+y)
#+END_SRC
So this is not much different than in Python for example:
#+BEGIN_SRC python
>>> def add (x,y):
... print x
... print y
... print (x+y)
... return x+y
>>> add(3,4)
3
4
7
7
#+END_SRC
But one /huge/ difference is the type inferred will be different:
#+BEGIN_SRC haskell
pureadd :: Num a => a -> a -> a
ioAdd :: Num a => a -> a -> {-hi-}IO{-/hi-} a
#+END_SRC
The consequence is that you will only be allowed to use =ioAdd= in function
whose type is also =IO *= for some value of =*=.
#+BEGIN_SRC haskell
circonference :: Int -> Int -> Int
circonference height width = pureadd (2 * height) (2 * width) -- OK
circonferenceIO :: Int -> Int -> Int
circonferenceIO height width = ioAdd (2 * height) (2 * width) -- WON'T COMPILE
#+END_SRC
To fix it you could simply change the type of the calling function:
#+BEGIN_SRC haskell
circonferenceIO :: Int -> Int -> IO Int
circonferenceIO height width = ioAdd (2 * height) (2 * width) -- OK
#+END_SRC
Now, I think, that's it. With that understandment, you should now be able to do
usefull thing with Haskell.
The why is it this way? Why adding that layer of complexity?
Just follow me, the answers will come in time.
** TODO Use External Library
** TODO Command Line Application
** TODO File Access
** TODO DB Access
** TODO REST API
** TODO Conclusion
Congratulation for going this far. Now you should be able to work in Haskell at
least as well as in any other programming language.
Now there are different directions:
- learning more libraries
- learn to optimise code to make it as fast as C
- learn to understand details of the compilation and Haskell
- learn tips and tricks
- learn more about abstractions and type classes
- learn parallel and concurrent programming
- learn to deploy like a pro using nix
The order in which to learn all thoses things can be very different for everty need.
* TODO Most common next steps
** TODO Enhance reproductibility with docker
** TODO Enhance reproductibility with nix
** TODO How to deploy?
There are plenty of ways de deploy
*** Trashy and easy
Compile in docker and copy the binary.
*** With =nix= and =nixops=
** TODO Code organisation
*** No organisation, everything in IO
** TODO Lenses
This will only be an introduction for being an user of the library.
** TODO Generics and lens-generic
** TODO Common Type Classes
*** Monoid
*** Functors
*** Applicative
*** Monads
*** Arrows
** TODO Monads Transformers
** TODO MTL
** TODO Dhall