Hacker News new | past | comments | ask | show | jobs | submit login
Haskell web programming (a simple tutorial) (yannesposito.com)
207 points by yogsototh on Jan 20, 2012 | hide | past | favorite | 60 comments



I'm having a hard time understanding the intent behind "You shouldn't need to know Haskell". Do you mean in order to complete the tutorial and understand what Yesod does? That's probably true. Being someone who's been studying and using Haskell in personal projects for the past maybe 10 months or so, Haskell's syntax and fundamental design decisions (while spot on, in my book) are different enough from most programmers' skill sets that I don't think they'll make it very far writing a non-trivial Yesod app without knowing Haskell. I'm fairly proficient/enamored with Haskell now but I'm certain I would have crashed and burned if I got my start trying to learn Haskell from Yesod.

My first dose of Haskell was attempting to write an XMonad config. That turned out to be a frustrating, several hour long ordeal for me that had me write off Haskell as undecipherable, alien hieroglyphics for quite some time after that. I'd urge anyone reading the tutorial who likes what they see to put in the hard time to get a handle on the language, understand what its good for and what it isn't and then return to web programming with it.


I am sorry if I didn't made it clearer. Of course, you don't need to know Haskell to follow this tutorial in particular.

But it is clear in my mind, you must know Haskell to do something useful with it. And in particular, make a web application, even if using a web framework.

As you stated, Haskell is not a language you could learn in 3 hours like I learned the bases of Python. It takes a very long time to learn, particularly when you're not used to functional programming.

But an intent of this tutorial was to promote Haskell. Clearly, if someone want to do something a bit more useful, he will very soon realize he must understand Haskell.

I added a specific advice in my conclusion similar to yours and pointing some essential resources.


Many people saw Ruby for the first time when they looked at a Rails tutorial. Many people see Python for the first time when they look at a Django tutorial. In both cases, you'd still need to learn more about the language to do something useful. I think the disclaimer "You shouldn't need to know Haskell" just means that the same thing works for this tutorial: you don't need to have seen Haskell before going through the tutorial, because you'll learn enough to follow the tutorial, even though you'll need to learn more later.


Is there performance benchmark comparing Haskell and Erlang? I hear Erlang is also quite performant when handling a large number of requests, but no hard numbers. Are there similar web frameworks for Erlang as Yesod for Haskell?

Also, what about Clojure? That runs on the JVM but how does it fare on the "correctness" claim of Haskell, i.e., "If it compiles it's close to what the programmer intended".

I'm learning Haskell right now and really loving it. I wonder if I should stick with it for more production projects or make a switch to Erlang/Clojure. I know Erlang has quite a few success stories behind it, CouchDB being one of them.


I think it would be uncontroversial to say that optimized GHC Haskell (statically typed, compiled, optimized, native code) is always faster than current Erlang implementations (dynamically typed, interpreted, lightly optimized).

For example, the fastest Erlang programs on the benchmarks game are all slower than all the GHC Haskell programs,

* http://shootout.alioth.debian.org/u64q/benchmark.php?test=al...

Median slowdown relative to GHC is 7x.

GHC is aiming for the high performance computing world of late, as well. The Erlang language just doesn't have the facilities for raw number crunching that's needed.


Erlang is interpreted. Since this is not about a simple CGI application a benchmark in which you compare the running time of a compiled executable with the interpretation and running time a another program it doesn't make a lot of sense.

Also this performance usually isn't the best way to argument about languages for web applications. Often your bottleneck is somewhere else and i you really have resource intensive stuff why not just interface C?


>Erlang is interpreted

No it isn't, it is compiled to bytecode and executed on a virtual machine, just like most scripting languages are.

>Since this is not about a simple CGI application a benchmark in which you compare the running time of a compiled executable with the interpretation and running time a another program it doesn't make a lot of sense.

Read the site, this concern is explicitly addressed. The tests are long running, not short tests repeated a million times. So the byte code compilation step ends up too small to notice. That is why using a PHP bytecode caching plugin doesn't increase PHP's performance on the shootout, and why java isn't dead last from the massive startup time of the JVM.

>Also this performance usually isn't the best way to argument about languages for web applications

This is a myth. Very few web applications actually have one CPU intensive portion that can be moved out into a C module. Most web apps have pretty flat profiles, where overall language speedups make the biggest difference. When 90% of your time is spent in 10% of the code, a C module is a reasonable option. When 90% of your time is spent in 90% of your code, your only option is a faster language.


It's always controversial to claim performance numbers without any actual evidence. Note that shootout numbers are by far not evidence about web-server performance.


Argument from authority is not much of an argument, but dons is intensely focused on ghc performance, here's an easy to google example. http://donsbot.wordpress.com/2010/02/21/smoking-fast-haskell...

It's not to hard for you to go get benchmark numbers in haskell, check out http://www.serpentine.com/blog/2009/09/29/criterion-a-new-be... or read about how snap does its benchmarking.

As for erlang, there's a lot of papers about reliability. I'm not saying the performance isn't there, it's just not a focus of the erlang community. You'll have a much tougher time figuring out instruction counts for a given function in erlang. Given that erlang is interpreted, without a major focus on performance, it seems unlikely erlang would be quicker.

This is just - what i perceive as - the general consensus. I'd love for you to generate some numbers to prove me wrong.


If you're looking for an Erlang web framework check out Chicago Boss. Brand new tutorial and everything:

http://www.chicagoboss.org/

Of course, the project still needs some performance work, as highlighted in this post:

http://labs.evolope.com/post/16054431816/a-comparison-of-web...

So CB is a long way from its theoretical maximum (largely because I haven't done any performance engineering on it yet).

"Performance", by the way, depends largely on the task at hand. For complex template rendering/delivery, Erlang will probably beat anything out there because of Erlang's intelligent use of immutable data and I/O lists. Most other languages do a "memcpy" for every chunk of the template as it's being built into a final string. Erlang, on the other hand, keeps around pointers to the separate pieces of memory and then does a scattered write (writev) when it's time to send the result to the client.


>For complex template rendering/delivery, Erlang will probably beat anything out there because of Erlang's intelligent use of immutable data and I/O lists.

What templating engine are you talking about? I'd assume ErlyDTL for obvious reasons, but it is certainly not beating "anything out there". Are you just comparing it to scripting languages or what?


  > Also, what about Clojure? That runs on the JVM but how
  > does it fare on the "correctness" claim of Haskell, i.e.,
  > "If it compiles it's close to what the programmer
  > intended".
Clojure's a dynamic language, so fairly different in character and strengths. Save for a couple of statically typed Lisp dialects, provability/correctness/etc. is not really what that language family is all about.

If you want JVM and reasonably advanced type systems (given that Haskell's claim to correctness essentially boils down to this), try Scala.


Hmm, that google search leads to this ugly exchange, mid 2010:

http://news.ycombinator.com/item?id=1448463

Anyway, benchmarks will always show GHC beating Erlang/BEAM, but here's a Simon (or one of his co-authors)saying that he's not into reinventing wheels, he's just going to copy good parts of erlang:

http://blog.romanandreg.com/post/6797527470/erlang-and-haske...

slide 41's pretty funny (by akka author):

http://www.slideshare.net/jboner/akka-scala-summit-oscon-201...

I have a hazy recollection of a F# user or maybe a Softie saying they're doing the same thing with MailboxProcessors, but i can't google it. Who/why are all these people borrowing/copying/appropriating from OTP behaviors?


From the bit of Haskell I've managed to learn, it's a great language, and I can see how an awful lot of the errors that you can make in other languages will probably be avoided in Haskell, but I've never understood the (frequently repeated) claim that

"If your program compile it will be very close to what the programmer intended".

There's nothing I've seen in Haskell, or any other language, that will prevent you implementing the wrong algorithm, or the wrong business rules etc. If you're doing a phsyics simulator (to take an example I've played around with), Haskell is not going to stop you badly miscalculating the gravitational effect of multiple objects, or calculating the mass of an object incorrectly.


That's the difference between an "intentional bug" and an "unintentional bug".

The former is when you want the program to do X, and X itself is wrong. Sure, defending against this is rarely possible. The latter is in my experience far more common. When you want the program to do X, but you actually told it to do Y.

Haskell catches most of the latter cases.

One of the main reasons is the functional purity. Because return values are the only result of a function, and these values are type-checked against a specification, it is much harder to do the wrong thing.

For example, an imperative program will idiomatically have methods whose sole effect is mutating their arguments or the objects. Even with a type system -- if you just omit the effects, the compiler really has no way to know that you meant the effects to happen, and you will simply have a bug. A purely functional program will idiomatically use a different style. Instead of mutating arguments and objects, it will return a new value. If you forget to return a new value, the compiler will catch that.

Additionally, the types in Haskell are generic by default. The more generic the type of a function, the more restricted is what that function can do. The restrictions narrow the space of wrong things you can do.

Another interesting property of Haskell is where it chooses to be on the "restrictiveness+guarantess vs. powerful+unguaranteed" trade-off.

It seems many don't even notice that the other side of the "power" coin is "guarantees". The more powerful a construct is -- the less you can say about what it will do. In Haskell, the purity and generic types of functions are two things that heavily restrict code. But there are many other mechanisms to restrict rather than empower code. In many contexts, restrictiveness is considered a bad thing, but in Haskell, this restrictiveness is very useful for reasoning about code.

For example, the function of type: (forall a. a -> a) in Haskell can only be the identity function. It cannot print "hello world", and it cannot mutate variables. These restrictions are useful because we now can have useful laws. For example: id . f = f . id = f. And we can derive these useful laws from the type itself, without even looking at the code!

By helping us find the most restrictive sub-language that can express the solution, we rule out even more bugs.


The power/guarantee trade off isn't a fundamental one, even though in current languages you often have to choose between the two. Creating languages that combine the power of untyped languages with the guarantees of static languages is an active field of research. For example, dependently typed languages, while currently too unwieldy for everyday use, show promise of having both power and guarantees much stronger than Haskell. Now a third, ill-defined axis of "usability" comes into play.


"The power/guarantee trade off isn't a fundamental one, even though in current languages you often have to choose between the two."

It is on the Pareto frontier of the two. Which verges on tautological, but it's still a useful observation. If you can trivially extend the power of a construct while maintaining the same guarantees, the construct was simply broken, and extending the guarantees of a construct without affecting its power means simply that the guarantees were excessively conservative in the first place.

(This can almost be copied and pasted any time anybody claims two properties of a program aren't in conflict, the most common probably being security and ease of programming.)

We may be wrong about where the frontier is... but I doubt we've very wrong.


I may be alone, but I actually feel like I lose power when using say dynamic languages. There is less power of expression. Sure I can do whatever I want, but in reality programming is communication, and I find them much less powerful in that respect.

So using an untyped language only to run an analysis on it later doesn't really seem all that appealing to me, even if it could somehow provide the guarantees of Haskell or dependently typed languages.


Defining them as "intentional bugs" doesn't seem particularly accurate or useful.

Some of them may class as "design" rather than "coding" bugs but they still aren't usually what the programmer intended, and I would say that the majority of production defects that I see in our systems these days would fall into this category.


In my experience the programmer workflow is (mostly):

  1. You think about an algorithm
  2. You (try to) code it
  3. A first time to discover an error: compilation and/or syntax verification.
  4. Then you test your code
Depending of the task and the fail, if 3 or 4 fail you go to 2 or 1.

With a standard language (C/C++/Java/Python/Ruby/Javascript...) The probability of 3 to fail is very small when you are used to your language. But the probability to fail at step 4 is High.

In haskell this is exactly the opposite, with many advantages:

Compiler error in Haskell gives you a meaningful and informative message. Most of the time, it even gives you a hint on how to solve the problem.

In the end, most of the time, once the compilation phase passed, my program worked as I expected.

Furthermore, with Haskell you can use quickcheck, which most of the time will make better test than yours. I know there is some quickcheck equivalent in other languages but I believe this is not standard.


The expression I had heard was "If your program compiles, it probably does something useful - though maybe not the thing you wanted".


I love Peaker's answer. To elaborate with a sort of concrete example of how haskell can help you avoid logic bugs as in your physics simulation example:

In code where the types start to to tell you less, e.g. when doing a bunch of number crunching, and you have a signature that looks like:

    func :: Int -> Int -> Int -> Int
It's common for the programmer to use a "newtype wrapper" to bring some of the logic into the type system like:

    newtype Velocity = Velocity Int
    newtype Force = Force Int
    newtype Iteration = Iteration Int
Then the type system will catch if you accidentally use the Velocity when what you want is Force, etc.



Most languages can help you avoid using the wrong one through the use of variable names.

The problems you might run into are more (for example) using the wrong algorithm for calculating gravity, adjusting the position of one planet before using it to evaluate its impacts on other planets, failing in collision detection etc.

I don't see anything in Haskell that would prevent me from doing any of those.


>Most languages can help you avoid using the wrong one through the use of variable names.

That doesn't help at all, are you serious? Cause you genuinely sound like you are trolling. Especially when you say things like "if a language can't prevent every possible bug then there's no poing having it prevent any bugs".


I think if someone made a language where it was categorically impossible to do something dumb they'd be very rich indeed. :)


As long as it was also possible to do some non-dumb things, of course...


true, otherwise you could just run your program by piping it into cat.


Spelling corrections, noted as I read:

"point of vue" -> point of view

"shell command are executed" -> "shell commands are executed"

"benchmark are here" -> "the benchmarks are here"

Also, heroku works just fine with haskell, as long as you compile a static binary on an ubuntu machine. I compile mine on virtual box (via way of vagrant), and have 3 haskell apps (none of them really production ready though) running on heroku right now.

Lastly, I don't really think haskell is the right language for a lot of web programming. In haskell, you really want your logic to be as purely functional as possible, but that gets pretty hard to do for web apps that rely on external apis.


Thanks! Spell errors corrected!

When I said there is no heroku for Haskell it because it is not official. Furthermore, do you have to use a 64bit architecture when compiling (just curious)? I might try it myself.

And I even think that the argument against the number of Haskellers is in fact a force instead of a drawback. It filter passionate people.

By external APIs, you mean that it would be difficult to write a simple "connect to twitter/facebook" application? Could you tell us about any bad experience you had?


Yeah, 64bit.

I never said anything about number of people...

External apis: nearly all the logic in my app leads to either talking to the db, or calling an http api (and haskell can't use https apis that well, you have to use its bindings to libcurl). In general, it feels extremely difficult to pull my logic out of IO (but maybe I'm just too dumb to).

It's not that its particularly difficult, it's just that it's not a problem I think haskell is well suited to solve. I've used haskell to teach my self automated logic proofs (just resolution refutation), compression algorithms (huffman encoding and lz77), typechecking and breaking encryption (enigma). Every time university exams roll around, I learning them on paper. It's by far and away the best language I've used for stuff like that. It feels like web-apps with lots of IO aren't really a problem haskell is well suited to solve.


Is anyone here using haskell or a similar funtional language for any web app?

Would be interested in known your experiences and opinion compared to something like django or rails.

How difficult is it to build something with a complex domain model?


I wrote https://serialist.net/ with one other person, entirely in Haskell. Serialist crawls comics and other serial content, derives the serial structure from the link graph, lets people maintain bookmarks in various serials, and tells you when new pages exist. The crawler, the graph algorithms, the database code, and the web interface all use Haskell, and the whole thing consists of a couple thousand lines. I would highly recommend it, especially for anything with a complex domain model.

The one caveat I'd suggest from experience: good web frameworks exist now, so use them, and don't write your own like we did. I'd recommend Yesod.


JanRain's auth/capture system runs on Haskell's 'snap' web server: http://corp.galois.com/blog/2011/4/22/tech-talk-video-haskel...


>Is anyone here using haskell or a similar funtional language for any web app?

Yes.

>Would be interested in known your experiences and opinion compared to something like django or rails.

Rails is an abomination, so pretty much anything would be better than that. We rolled our own framework in scala. Despite initial resistance from some dynamic language proponents here, it is now the only thing anyone here will use for web development. Even the python fan won't touch django now.

>How difficult is it to build something with a complex domain model?

Easier than in dynamic languages. The problem with complex models is that humans can't hold all that information in their heads. Static typing lets us offload a bunch of important information to the compiler and have it error check for us as we go. Our biggest issue has been that scala isn't strong enough, I'd much prefer to be using haskell.


>Our biggest issue has been that scala isn't strong enough, I'd much prefer to be using haskell.

I hear that. I learned Haskell because I thought it would help me understand Scala better (namely the type system), but Haskell spoiled me and I don't want to use Scala anymore. Only thing keeping me on Scala atm is Lift, a truly excellent rethinking of web frameworks. If I ever find the time I want to start porting Lift to Haskell.


I'm not a huge fan of lift, but the portion of it I am ok with (the templates/snippets side of things) is fairly similar to how you use snap. It may be worth it to work on helping to finish snap (or forking it if need be) rather than starting from scratch. Snap currently provides nothing for database access, so you have a blank slate there to copy mapper or record from lift (but those both suck horribly!).


Interesting, what aspects are you not a fan of (besides the persistence parts)?


The model side of things is certainly my biggest complaint. The other things are minor in comparison, but still annoying. I like the architecture of lift, just not some of the details of the implementation.

I don't like the way templates are forced to use snippets to load data, in particular as it results in snippets being dependent on the database, and thus not suitable for unit testing. The framework should be pulling the data into the view, which then passes it as an argument to the snippet to do whatever transformation on it. That way snippets are entirely self-contained and easy to unit-test. This is the sort of thing that I think would have ended up the way I want had it been written in haskell instead of scala just because writing small, self-contained functions is the typical haskell way of doing things.

I hate the very opinionated nature of the form handling, and the even more opinionated responses from the developers to questions like "how can I make a form that works normally and doesn't require a session". People are not bad for wanting forms to behave normally, and the "security" show the lift devs put on to justify the form handling in lift is insulting.

While I find templates acceptable, they are seriously missing out on type safety. I should get a compiler error if I create a template with invalid html. Ocsigen got this part very right (an ocaml framework/appserver). Not only do I not get this benefit for my markup, but lift itself generates invalid html on me when using virtually any of the included form generation methods. Very annoying.

Ideally what I want is a framework that gives me the type safety of yesod, but with the structure of lift. I hate faux-mvc web frameworks and find they make things more difficult rather than making things easier, and unfortunately yesod copies the typical rails clone structure. Lift doesn't make the mistake of trying to hide http from me, and gives me the simple and correct mapping of template to url, leaves the domain model in the model instead of cramming it into "controllers" that shouldn't be involved.


Thanks. Those haven't bothered me too much yet, but good to have on the radar. That's the first real critique of Lift I've seen, other than 'it's not MVC'.

As for Yesod, I was also thinking it would be nice to have the type safety and parallel/concurrent performance of Yesod with the templating and structure of Lift. Don't know Yesod well enough yet though. Too many side projects.


No interest in starting a flame-war, but as someone who's just getting going learning to code, I'm curious why you would call Rails an abomination. Can you explain in a way a complete beginner would understand?


I can try. Basically it is a PHP framework written in ruby. It has a really poor API that makes for very error prone coding. It completely fucked up the entire MVC architecture, creating a big fat controller layer that contains logic that belongs in the model. This makes it impossible to re-use code as much as it should, and makes unit testing much harder as there's too many inter-dependencies. And monkey-patching is the norm with rails, which causes all sorts of bugs. Monkey-patching is basically changing the API of existing classes, so then other libraries you might use break because the API they are expecting from the ruby library has changed on them.


Right , I get that static typing can be an advantage but how is the functional paradigm an advantage in this case?

Or is it more than you just want to use something statically typed that isn't Java?


Ah, yes we weren't looking for functional languages specifically, just languages with expressive type systems. As far as I know, the only languages with expressive type systems are also functional so we end up with a functional language as a consequence of that requirement, not due to actively seeking a functional language.

We use scala in a pretty functional way, but most of the gains there come in the processing/displaying side rather than the model. Just because that portion lends itself to a functional style of applying chains of functions on data to transform it.


What do you mean by "strong" enough? Are you just talking about strongly typed?


Yes. Scala lets you bypass the compile time type safety pretty easily, and as a result tons of libraries do precisely that. Take squeryl for example, it advertises itself as a type safe DSL for querying databases, but virtually anything you throw at it will compile, and then results in run-time exceptions.


    You shouldn’t need to know Haskell. 

    Don’t pay attention to all the syntax. 

    If you are curious you can take a look at Applicative Functor. 
This is a nice, whirlwind tour, maybe the opening benchmarks and jab at node are superfluous. All haskell tutorials hit the speedbump of how to bootstrap haskell understanding, where to make forward references and when to say "Trust me" but code shown here: do blocks, ($), <- and return would be confusing if you didn't know any haskell


Should I add a link to this article[^1] for people confused by the Haskell syntax?

The opening is not really an attack. This is the way I myself started to be interested in Haskell web programming.

[^1]: http://blog.ezyang.com/2011/11/how-to-read-haskell/


Yah, maybe just add links at bottom: LYAH, Applicative Functor wiki page. Or maybe mention one syntax feature, IO's and do-blocks, and say "return" and "<-" just kick things into and out of IO's, loosely speaking. Just don't say IO's are like burritos ;-}

You could also say, for anybody that's looked at lisps, *ML, F#, scala, erlang, the syntax isn't too bad, and for anybody that knows rails, they'll recognize the same REST'y MVC layers/abstractions. I gather the target audience is folks using dynamically typed languages.


Finally I know how to draw owls.


  Haskell web frameworks handle parallel tasks perfectly. For example even better than node.js
of course, node.js has no parallelism


I think what was meant was concurrency. Haskell's lightweight user-space threading runtime is modeled after Erlang's.


haven't finished reading the whole content, but the zoom in zoom out effects are very annoying.


Are you talking about the zoom in when you click on some code block? I was thinking to remove them.


the Ctrl + , or Ctrl mouse scroll up or mouse scroll down


For me, it takes only one to two second animation. After it stabilize. You can disable javascript and there won't be any CSS animation added.


for me, in chrome, it takes 8-10 seconds to stabilize. and looks really wonky


I disabled animation for chrome.


Hey your site is really pretty. Would you mind licensing your CSS for personal use? I'd like to use for my blog (which I will start one of these days).

Very nice blog post. After working on a Python stack during my part time job (check out Apache libcloud), I can safely say that using a statically typed language is a necessity for any non-trivial project. Without a type system you offload the entire framework onto the programmer. To actually grok the project you have to hold the complexity all in your head instead of using the types as a guide and that makes getting started incredibly challenging.


Thanks.

The source code of my website is here:

https://github.com/yogsototh/Scratch/

And even if not clearly stated, everyone is free to use it and steal from it. Of course, I'd appreciate to be mentioned.

If you want to have the full behavior you should copy not only the css but a bit of js.

More precisely:

  output/Scratch/css
  output/Scratch/assets/css
  output/Scratch/js/init.js
  + jquery
You should have a functioning website which will be iPhone/iPod friendly.

You certainly also need to get the layouts:

  layout/article.html
  layout/default.html
Unfortunately, I didn't finished to switch to HTML5, the current code is XHTML strict 1.0. You can have a preview of my HTML5 transition if you look at the html5 branch. But I'll have to duplicate a lot of CSS modifications since.

If you want any more information, simply mail me, I'll be happy to help.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: