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.
|
|
|
|
|
2018-01-01 17:04:50 +00:00
|
|
|
The problem I try to solve in this book is to make you a professional "user" of
|
|
|
|
Haskell more than a "contributor" to Haskell. While I encourage everybody to
|
|
|
|
gain deeper understanding on the internals of Haskell this is not the primary
|
|
|
|
goal of this book.
|
|
|
|
|
|
|
|
What I mean by professional "user" is that you should have the following
|
|
|
|
features at your disposal:
|
|
|
|
|
|
|
|
- DCVS
|
|
|
|
- Generated documentation
|
|
|
|
- Tests (Unit tests, Generative tests, Integration tests, etc...)
|
|
|
|
- Benchmark
|
|
|
|
- Continuous Integration
|
|
|
|
- Continuous Deployment
|
|
|
|
|
|
|
|
Choices:
|
|
|
|
|
|
|
|
- Raw: get GHC and cabal exectuable and work with that. Too long and manual
|
|
|
|
- Nix: this is really great because it's like a super make that can deal with
|
|
|
|
external dependencies. Certainly the best best in the long term.
|
|
|
|
- Stack: fast to install focused on being user friendly. Has a lot of easy to
|
|
|
|
use features like:
|
|
|
|
- integration with docker that will make it easy to cross-compile.
|
|
|
|
- integration with nix
|
|
|
|
- easy to deal with many private repositories
|
|
|
|
- good professional starting templates
|
2017-12-30 23:07:49 +00:00
|
|
|
|
|
|
|
*** Stack
|
|
|
|
|
|
|
|
I recommend [[https://haskellstack.org][stack]]. But there are many different method to install Haskell.
|
2018-01-01 17:04:50 +00:00
|
|
|
Stack should be simple and straight to the point.
|
2017-12-30 23:07:49 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
|
2018-01-01 17:04:50 +00:00
|
|
|
*** Stack template
|
2017-12-30 23:07:49 +00:00
|
|
|
|
2018-01-01 17:04:50 +00:00
|
|
|
Before starting to write your first line of code.
|
|
|
|
Let's create a project with a sane and modern file organisation.
|
2017-12-30 23:07:49 +00:00
|
|
|
|
2018-01-01 17:04:50 +00:00
|
|
|
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.
|
2017-12-30 23:07:49 +00:00
|
|
|
|
|
|
|
Mainly do jump into programmin you could theoretically just download the binary
|
2018-01-01 17:04:50 +00:00
|
|
|
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.
|
2017-12-30 23:07:49 +00:00
|
|
|
|
|
|
|
So let's start with a sane professional organisation for your files.
|
|
|
|
|
|
|
|
#+BEGIN_SRC shell
|
2018-01-01 17:04:50 +00:00
|
|
|
stack new myproject https://goo.gl/5bUVXg
|
|
|
|
#+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
|
2017-12-30 23:07:49 +00:00
|
|
|
#+END_SRC
|
|
|
|
|
2018-01-01 17:04:50 +00:00
|
|
|
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.
|
|
|
|
|
2017-12-30 23:07:49 +00:00
|
|
|
*** Editor
|
|
|
|
|
2018-01-01 17:04:50 +00:00
|
|
|
You should check any of the supported editor here:
|
|
|
|
|
|
|
|
https://github.com/rainbyte/haskell-ide-chart#the-chart-with-a-link-to-each-plug-in
|
2017-12-30 23:07:49 +00:00
|
|
|
|
2018-01-01 17:04:50 +00:00
|
|
|
I personnaly use [[http://spacemacs.org][spacemacs]] with the haskell layer because it comes with battery
|
|
|
|
included. If you're not used to vim keybindings I believe it is easy to switch
|
|
|
|
to more classical editor keybindings easily.
|
2017-12-30 23:07:49 +00:00
|
|
|
|
2018-01-01 17:04:50 +00:00
|
|
|
Even if I don't have a strong opinion on the editor you should choose.
|
|
|
|
It should at least be easy to support the Haskell tooling, like intero or ghc-mod.
|
|
|
|
Because it's one of the best part of Haskell.
|
2017-12-30 23:07:49 +00:00
|
|
|
|
2018-01-01 17:04:50 +00:00
|
|
|
For example without any configuration I have the following features:
|
2017-12-30 23:07:49 +00:00
|
|
|
|
2018-01-01 17:04:50 +00:00
|
|
|
- I see errors, warn and even code hints while I'm typing my code.
|
|
|
|
- very good code completion
|
|
|
|
- auto styling of my source code and be able to change the style of my entire buffer
|
|
|
|
- be able to get the type of the expression under my cursor
|
|
|
|
- be able to add the type of a top level declaration
|
|
|
|
- be able to launch a repl easily loading the current code of the file I'm
|
|
|
|
currently editing
|
|
|
|
|
|
|
|
And many other nice features.
|
|
|
|
|
|
|
|
Note that in the past I had some problem with ghc-mod during upgrades while
|
|
|
|
intero was mostly a no problem story.
|
2017-12-30 23:07:49 +00:00
|
|
|
|
|
|
|
It is also useful to have hoogle and hayoo, which are search engine focused on Haskell.
|
|
|
|
|
2018-01-01 17:04:50 +00:00
|
|
|
**** Spacemacs
|
|
|
|
|
|
|
|
So if you want to choose spacemacs:
|
|
|
|
|
|
|
|
1. Install a recent emacs
|
|
|
|
2. =git clone https://github.com/syl20bnr/spacemacs ~/.emacs.d=
|
|
|
|
3. Launch emacs
|
|
|
|
4. Edit your =~/.spacemacs= file to add to the layer list:
|
|
|
|
|
|
|
|
#+BEGIN_SRC elisp
|
|
|
|
haskell
|
|
|
|
(auto-completion :variables
|
|
|
|
auto-completion-enable-help-tooltip t
|
|
|
|
auto-completion-enable-short-usage t)
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
If you're not used to vim keybinding and it is too much to handle for you.
|
|
|
|
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.
|
|
|
|
|
|
|
|
*** Conclusion
|
|
|
|
|
|
|
|
First congratulation to have perseverred until there.
|
|
|
|
|
|
|
|
I know it was already a lot of boring tasks to perform before being able to
|
|
|
|
write any line of code. But I promise it will be worth it. Going this route
|
|
|
|
you'll short circuited a lot of detours.
|
|
|
|
|
|
|
|
By starting with this template, you won't use the classic prelude. It's quite a
|
|
|
|
strong opinionated move. Because many classic function will be overwritten by
|
|
|
|
safer/more generic one.
|
|
|
|
|
|
|
|
So be prepared that the actual learning route is jumping other classical
|
|
|
|
learning steps you can find in other learning resources. Don't worry I'll do my
|
|
|
|
best to make the jump as natural as possible.
|
|
|
|
|
2017-12-30 23:07:49 +00:00
|
|
|
* 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
|