## Why Haskell?
![Impressive Haskell Benchmark](http://yannesposito.com/Scratch/img/blog/Yesod-tutorial-for-newbies/haskell-benchmark.png)
Its efficiency (see [Snap Benchmark][snapbench] _&_
[Warp Benchmark][warpbench][^benchmarkdigression]).
Haskell is an order of magnitude faster than interpreted languages
like [Ruby][haskellvsruby] and [Python][haskellvspython][^speeddigression].
Haskell is a high level language and make it harder to shoot you in the foot
than `C`, `C++` or `Java` for example.
One of the best property of Haskell being:
> "If your program compile it will be
> very close to what the programmer intended".
Haskell web frameworks handle parallel tasks perfectly.
For example even better than node.js[^nodejstroll].
From the pure technical point of view,
Haskell seems to be the perfect web development tool.
Weaknesses of Haskell certainly won't be technical:
- Hard to grasp Haskell
- Hard to find a Haskell programmer
- The Haskell community is smaller than the community for `/.*/`
- There is no [heroku](http://heroku.com) for Haskell (even if [Greg Weber did it](http://www.yesodweb.com/blog/2011/07/haskell-on-heroku), it was more a workaround).
I won't say these are not important drawbacks.
But, with Haskell your web application will have both properties
to absorb an impressive number of parallel request securely
and to adapt to change.
Actually there are three main Haskell web frameworks:
1. [Happstack](http://happstack.com)
2. [Snap](http://snapframework.com)
3. [Yesod](http://yesodweb.com)
I don't think there is a real winner between these three framework.
The choice I made for yesod is highly subjective.
I just lurked a bit and tried some tutorials.
I had the feeling yesod make a better job at helping newcomers.
Furthermore, apparently the yesod team seems the most active.
Of course I might be wrong since it is a matter of feeling.
![1. Draw some circles. 2. Draw the rest of the fucking owl](http://yannesposito.com/Scratch/img/blog/Yesod-tutorial-for-newbies/owl_draw.png)
Why did I write this article?
The yesod documentation and particularly the book are excellent.
But I missed an intermediate tutorial.
This tutorial won't explain all details.
I tried to give a step by step of how to start from a five minute tutorial
to an almost production ready architecture.
Furthermore explaining something to others is a great way to learn.
If you are used to Haskell and Yesod, this tutorial won't learn you much.
If you are completely new to Haskell and Yesod it might hopefully helps you.
Also if you find yourself too confused by the syntax, it might helps to read this
[article](http://blog.ezyang.com/2011/11/how-to-read-haskell/)
During this tutorial you'll install, initialize and configure your first yesod project.
Then there is a very minimal 5 minutes yesod tutorial to heat up and verify the awesomeness of yesod.
Then we will clean up the 5 minutes tutorial to use some "best practices".
Finally there will be a more standard real world example; a minimal blog system.
[warpbench]: http://www.yesodweb.com/blog/2011/03/preliminary-warp-cross-language-benchmarks
[snapbench]: http://snapframework.com/blog/2010/11/17/snap-0.3-benchmarks
[^benchmarkdigression]: One can argue these benchmark contains many problems. But the benchmarks are just here to give an order of idea. Mainly Haskell is very fast.
[^speeddigression]: Generally _high level_ Haskell is slower than C, but _low level_ Haskell is equivalent to C speed. It means that even if you can easily link C code with Haskell, this is not needed to reach the same speed. Furthermore writing a web service in C/C++ seems to be a very bad idea. You can take a look at a [discussion on HN about this](http://news.ycombinator.com/item?id=3449388).
[^nodejstroll]: If you are curious, you can search about [the Fibonacci node.js troll](http://www.unlimitednovelty.com/2011/10/nodejs-has-jumped-shark.html). Without any tweaking, [Haskell handled this problem perfectly](http://mathias-biilmann.net/posts/2011/10/is-haskell-the-cure). I tested it myself using yesod instead of Snap.
[haskellvsruby]: http://shootout.alioth.debian.org/u64q/benchmark.php?test=all&lang=ghc&lang2=yarv
[haskellvspython]: http://shootout.alioth.debian.org/u64q/benchmark.php?test=all&lang=ghc&lang2=python3
## Before the real start
### Install
The recommended way to install [Haskell][haskell]
is to download the [Haskell Platform][haskellplatform].
[haskell]: http://www.haskell.org
[haskellplatform]: http://www.haskell.org/platform
Once done, you need to install yesod.
Open a terminal session and do:
~~~
~ cabal update
~ cabal install yesod cabal-dev
~~~
There are few steps but it should take some time to finish.
### Initialize
You are now ready to initialize your first yesod project.
Open a terminal and type:
~~~
~ yesod init
~~~
Enter your name, choose `yosog` for the project name and enter `Yosog` for the name of the Foundation.
Finally choose `sqlite`.
Now, start the development cycle:
~~~
~ cd yosog
~ cabal-dev install && yesod --dev devel
~~~
This will compile the entire project. Be patient it could take a while the first time.
Once finished a server is launched and you could visit it by clicking this link:
[`http://localhost:3000`](http://localhost:3000)
Congratulation! Yesod works!
> Note: if something is messed up use the following command line inside the project directory.
>
>
> \rm -rf dist/* ; cabal-dev install && yesod --dev devel
>
Until the end of the tutorial, use another terminal and let this one open
in a corner to see what occurs.
### Configure git
> Of course this step is not mandatory for the tutorial
> but it is a good practice.
Copy this `.gitignore` file into the `yosog` folder.
~~~
cabal-dev
dist
.static-cache
static/tmp
*.sqlite3
~~~
Then initialize your git repository:
~~~
~ git init .
~ git add .
~ git commit -a -m "Initial yesod commit"
~~~
We are almost ready to start.
### Some last minute words
Up until here, we have a directory containing a bunch of files
and a local web server listening the port 3000.
If we modify a file inside this directory, yesod should try
to recompile as fast as possible the site.
Instead of explaining the role of every file,
let's focus only on the important files/directories for this tutorial:
1. `config/routes`
2. `Handler/`
3. `templates/`
4. `config/models`
Obviously:
`config/routes` | is where you'll configure the map %url → Code. |
`Handler/` | contains the files that will contain the code called when a %url is accessed. |
`templates/` | contains %html, js and %css templates. |
`config/models` | is where you'll configure the persistent objects (database tables). |
http://localhost:3000/echo/<a>I'm <script>alert("Bad!");
The special characters are protected for us.
A malicious user could not hide some bad script inside.
This behavior is a direct consequence of _type safety_.
The %url string is put inside a URL type.
Then the interesting part in the URL is put inside a String type.
To pass from URL type to String type some transformation are made.
For example, replace all "`%20`" by space characters.
Then to show the String inside an %html document, the string is put inside an %html type.
Some transformations occurs like replace "<
" by "`<`".
Thanks to yesod, this tedious job is done for us.
```
"http://localhost:3000/echo/some%20text" :: URL
↓
"some text" :: String
↓
"some text <a>" :: Html
```
Yesod is not only fast, it helps us to remain secure.
It protects us from many common errors in other paradigms.
Yes, I am looking at you PHP!
### Cleaning up
Even this very minimal example should be enhanced.
We will clean up many details:
- Use a general CSS (cleaner than the empty by default)
- Dispatch handler code into different files
- Use `Data.Text` instead of `String`
- Put our "views"[^explainviewwidget] inside the `template` directory
[^explainviewwidget]: By view I mean yesod widget's hamlet, lucius and julius files.
#### Use a better CSS
It is nice to note, the default template is based on %html5 boilerplate.
Let's change the default %css.
Add a file named `default-layout.lucius` inside the `templates/` directory containing:
body {
font-family: Helvetica, sans-serif;
font-size: 18px; }
#main {
padding: 1em;
border: #CCC solid 2px;
border-radius: 5px;
margin: 1em;
width: 37em;
margin: 1em auto;
background: #F2F2F2;
line-height: 1.5em;
color: #333; }
.required { margin: 1em 0; }
.optional { margin: 1em 0; }
label { width: 8em; display: inline-block; }
input, textarea { background: #FAFAFA}
textarea { width: 27em; height: 9em;}
ul { list-style: square; }
a { color: #A56; }
a:hover { color: #C58; }
a:active { color: #C58; }
a:visited { color: #943; }
Personally I would prefer if such a minimal %css was put with the scaffolding tool.
I am sure somebody already made such a minimal %css which give the impression
the browser handle correctly %html without any style applied to it.
But I digress.
#### Separate Handlers
Generally you don't want to have all your code inside a unique file.
This is why we will separate our handlers.
In a first time create a new file `Handler/Echo.hs` containing:
``` haskell
module Handler.Echo where
import Import
getEchoR :: String -> Handler RepHtml
getEchoR theText = do
defaultLayout $ do
[whamlet|
<h1> #{theText}
and modify the handler `Handler/Echo.hs`:
``` haskell
getEchoR :: Text -> Handler RepHtml
getEchoR theText = do
defaultLayout $ do
$(widgetFile "echo")
```
At this point, our web application is structured between different files.
Handler are grouped, we use `Data.Text` and our views are in templates.
It is the time to make a slightly more complex example.
## Mirror
![Neo touching a mirror](http://yannesposito.com/Scratch/img/blog/Yesod-tutorial-for-newbies/mirror.jpg)
Let's make another minimal application.
You should see a form containing a text field and a validation button.
When you enter some text (for example "Jormungad") and validate,
the next page present you the content and its reverse appended to it.
In our example it should return "JormungaddagnumroJ".
First, add a new route:
/mirror MirrorR GET POSTThis time the path `/mirror` will accept GET and POST requests. Add the corresponding new Handler file: ``` haskell module Handler.Mirror where import Import import qualified Data.Text as T getMirrorR :: Handler RepHtml getMirrorR = do defaultLayout $ do $(widgetFile "mirror") postMirrorR :: Handler RepHtml postMirrorR = do postedText <- runInputPost $ ireq textField "content" defaultLayout $ do $(widgetFile "posted") ``` Don't forget to declare it inside `yosog.cabal` and `Application.hs`. We will need to use the `reverse` function provided by `Data.Text` which explain the additional import. The only new thing here is the line that get the POST parameter named "content". If you want to know more detail about it and form in general you can take look at [the yesod book](http://www.yesodweb.com/book/forms). Create the two corresponding templates: ```