I'm wondering how much benefit a CRUD-centric web application can benefit from Haskell's type system, particularly when the front end is built with a Javascript MVC framework like AngularJS which passes around typeless data objects.
It seems to me that as soon as you transform Haskell datatypes into JSON objects which you pass to a heavy JavaScript MVC framework layer, the benefits of having Haskell's type system as part of the web stack start eroding dramatically, as there is no way to let the type checker ensure the type-integrity of the data flow through the whole web application.
For example, you could change the database schema and the associated Haskell types, but the type checker won't be able to tell you what parts of the JavaScript MVC front-end need updating as well. I see this as a problem.
Am I stating the problem correctly, and if so, what advice could Haskell web application developers give on this point?
We've been wrestling with this exact same question quite a bit since we recently started a project with a substantial javascript front end. My anecdotal observation has been that we have a lot more bugs in the javascript application than we had with previous applications that just used Snap and generated HTML with Heist. We haven't decided on anything yet, but here are some of the possible solutions we've been considering:
These are pretty unsatisfying solutions to me. The improve slightly on Javascript, but don't come close to giving me the things that I get with Haskell.
The problem with these solutions (as well as with the previous group) is that if your back end is written in Haskell, you still have the impedance mismatch because your front end language is not Haskell. This makes your code less DRY because you have to end up defining the same data structures in Haskell and the front end language. And when you change them in Haskell, you don't get errors indicating where your front end code needs changing. The app just breaks.
The new game in town here is ghcjs. This is a very promising project, but I don't consider it to be viable for production at least until GHC 7.8 is released. That will hopefully happen within the next week. Once 7.8 is out the door, you still have to take into consideration that ghcjs is still very new. And even in the hypothetical scenario that it was 100% feature complete and the first release worked perfectly, you still have to remember that a fair amount of infrastructure has to be built before Haskell+ghcjs is as effective as high level javascript frameworks like Angular, Ember, etc.
UPDATE September 2016: Now, almost three years after I originally wrote this answer, GHCJS has improved greatly. There is still room for more improvements, but I have used it for production applications and it worked very well. It's especially powerful when combined with the Reflex FRP library that makes it much easier to build reactive UIs.
If you have a relatively constrained problem, it might be possible to do all your application work on top of an EDSL that generates javascript. We already have the fantastic jmacro package to take care of the low level concerns of generating Javascript. You could leverage that and generate code that uses whatever other javascript libraries are appropriate for your application. That could be javascript + jquery, D3.js, or even code using a higher level javascript framework like Angular or Ember. I tend to think that Angular would be much easier to generate code for than Ember because of its simplicity and stronger encapsulation.
This is just a pie in the sky idea of mine. I don't think it's really practical because it would take a huge amount of work and be very difficult to gain adoption. But I like to at least mention the idea for completeness. Others have pointed out that asm.js is almost like this already. That may be the case, but it would be nice to have things like tailcall optimization designed into the VM level from the start.
In my opinion, easy solution - generate typescript interfaces from haskell data declarations(or another api scheme descriptions) and use TypeScript for front-end part. it gives the opportunity to work on a project for people who do not know haskell, but who knows Javascript.
For example
data RpcResponse = RpcResponse { number :: Int, string :: Maybe String }
compile to
interface RpcResponse {
number : number,
string?: string
}
and function parseRpcResponseJson has Typescript type
parseRpcResponseJson(response: string): Option<RpcResponse>;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With