Haskell is an underrated super power for building backends and web apps. Since 2019 when the blog post was written the ecosystem has improved quite a lot. With the Haskell Language Server and the Haskell Plugin for VS Code there's now really nice editor support. The language itself also got major improvements, e.g. support for dot-notation has been added, so you can now write `someValue.someField` as in other languages.
If you're interested in Haskell and are doing web dev, check out IHP, Haskell's version of Laravel/Rails/Django: https://ihp.digitallyinduced.com/ (Disclaimer: I'm founder of the company that makes IHP)
That looks really interesting, and I want to also say that that is an exceptional landing page. It has a lot of useful information at just the right level to inform and interest me.
Looks like a good way of getting back into experimenting with haskell.
Slightly off-topic but how would you convince upper management or a fresh startup to use Haskell? What would be the selling points compared to more mainstream (non-lazy) functional choices?
I'm pretty fluent in Haskell, but finding Haskell jobs is hard compared to OCaml or F#, which are a bit of a niche of their own. Actually, I routinely get OCaml offers when advertising Haskell on my CV. I find this interesting and exciting as OCaml was not very frequent outside academia a few years back.
I think management would have to buy in on developer investment. People who want to work with Haskell, on average, seem quite devoted. I feel like those devs who really want to use Haskell at production scale truly believe in functional programming as a superior endeavor, also, most devs devoted to Haskell also love advanced type systems and are particularly drawn to deeper Haskell the more they do it.
Long statements, but I really do think employee retention and personal fulfillment would lead to a better working environment. So that is the way I’d argue it. Obviously a comprehensive sampling of performance metrics would be needed along with the more HR reasonings, but I think there are plenty of examples where Haskell is performing acceptably.
I just lost a big block of time because of this, please contextualize correctly that claim when you make it.
Support for dot-notation like it's documented at the proposals has been partially added. Field fetching is complete, field updates isn't released at all. It is being actively developed, and both bring very interesting features that you can't get in most languages - after all, it's Haskell - but it was only partially released up to now.
Can you explain what "interesting features that you can't get in most languages" it brings? Because in most languages, field fetching and field updates aren't novel at all...
Fetching and updates are rebindable operations that you can overload for specific types (well, like most languages properties), for everything on some part of your code, or even on the standard library.
I didn't know about the dot notation, very cool but at the same time kinda awkward in a functional setting, goes a little bit against the other type of haskell syntax, I think someField someValue syntax is more explicit.
I love Haskell, developed daily with it (side projects & libraries) for like five years, but I think it is way behind other languages when it comes to super basic tasks common to database-backed web applications like mapping a set of relational tables to a tree of data (think Company -> Contacts -> Addresses -> City, only a few layers deeper and more joins in order to find the right data-set) that can be serialized to JSON and sent to an API client. I literally could not find a way to do this without lots of slogging for every single query. And then if I want to take that graph of data back, and validate it and apply changes (like Elixir's Ecto Changesets) then god help me...I just have to write so much code to do something a library should be doing for me. And it seems nearly impossible to write that library in Haskell's type system. Would love to be wrong about this.
Agree, Haskell's works best when working with flat data structures. IHP also only supports one-level nesting depth, like this:
post <- fetch postId
>>= fetchRelated #comments
This is fine for simple form based CRUD apps.
As you mentioned you're consuming the data with a JS frontend: For these cases we added a subsystem called DataSync to IHP. DataSync allows to use the IHP query builder directly from the JS side. This way we basically avoid needing to hand-write these nested graph API responses. Complex forms that depend on a lot of complex data can now be implemented using React components.
Here's an example query call from the JS:
const todos = await query('todos')
.where('id', 'd94173ec-1d91-421e-8fdc-20a3161b7802')
.or(where('id', '173ecd94-911d-1e42-dc8f-1b780320a316'))
.fetch()
This way the frontend can query data that it needs just in time. And also write records to the database without needing to manually writing API actions (thus avoid the data tree problem).
You can find an example of this here: https://ihp.digitallyinduced.com/Guide/realtime-spas.html#bu... For web apps that are fully consumed by a single page app, we're right now building IHP Backend, which provides the IHP tooling + the DataSync API in a way that is way simpler than full stack IHP. If you're curious, you can find a demo video here: https://youtu.be/-jj19fpkd2c
I'm reluctant to say that it is impossible, because there are so many clever things that have been done with Haskell's type system that I can barely understand how to use, much less how to design those systems (like Servant's typed URLs). But from a naive user point of view, I don't see how its remotely possible to develop Ecto-style (or ActiveRecord style) associations with selective eager pre-loading, and typed validations against arbitrary trees of data with such a strictly typed system. And I think I've looked at every SQL library for Haskell and none of them really approach it.
I'm sure its possible to build something that compiles, but it would be so awful to use that you are better off with hand-written SQL where you need it, and N+1 stuff where you can get away with it.
That's awesome, thanks for linking it to me. I don't think I have seen this library before, looks like its fairly new. I have to admit from the signature I can't tell if I can nest these arbitrarily deep, it looks like I can?
Having said that, Postgres supports JSON fine, and Opaleye and Rel8 support Postgres's JSON fine, so you can just use that if you want arbitrarily structured and nested stuff.
If I understand this correctly: you are saying that strict-typing prevents arbitrary depth record requests to be made to SQL because Haskell cannot represent an arbitrary tree of types...
I presume that the accessors in Haskell would be 1-1 with SQL language requests, but the problem is that SQL queries are not typed? Or are dynamically typed?
So, instead of a generic library for SQL queries, one would have to implement a library for a specific SQL DB structure?
There are typed query libraries, like esqueleto which give you well typed and flexible query semantics, my complaint with it is that it just returns a tuple of lists, with a separate list for each type, you cannot return the data structured in a tree.
So if you have a companies table joined to a contacts table, you'd get a two element tuple with a list of companies and a list of contacts, and then you have to iterate to do the joins and turn it into a JSON tree.
And there is no help at all for wanting to take in a tree of JSON data, and turn it into updates to existing records and inserts for new records.
You could have a library that to knows how to return a tree if you define a typeclass for the tree, but the only way I'd know to do it would be a separate tree data type for each result set. In Ecto you do have to define a structure that knows all the possible associations, but which associations you actually load in any given query is flexible, you can have associations that are not loaded eagerly for one query, and loaded eagerly in another. In Haskell I can't imagine doing that without two different tree structs, because there is nothing that would know how to take two differently typed result sets and make the same tree partially loaded.
> So if you have a companies table joined to a contacts table, you'd get a two element tuple with a list of companies and a list of contacts, and then you have to iterate to do the joins and turn it into a JSON tree.
Esqueleto has a function to avoid n+1's and return a map now:
Thank you. I hope the strategy turns out great. But, you know, i18n is such a basic feature. You said "check out IHP, Haskell's version of Laravel/Rails/Django"...
Google actually offers a way to embed videos without there being cookies set. You just have to change the domain name. I think it's something like youtube-nocookies.com.
I mean, when we say "Anyone could do it." we mean "Anyone with a strong enough understanding of Haskell's syntax and type system to be able to formalize it" which is a surprisingly small number of people. It's probably smaller than the number of professional Haskell developers and that isn't that big a number.
I think that Haskell2010 could be the last Haskell standard. Modern Haskell has diverged to such a degree that it seems to be (almost) impossible to define a common standard. Even if they would, as long as there a over 100 language extension (increasing over time) there will be developers using them. Take a look at C++20, I think it's obvious that C++ is beyond repair at this point in time, even if you wouldn't add any more language features.
Sure, a new Haskell standard would allow for more compiler competition and that's a good thing, but it cannot fix the language. I think what we really need is a new language that picks all the good parts from Haskell, but has a very small syntactical core. Something like Go, but purely functional. You might say Rust or Elm. But Rust is too performance oriented and already quite big, hence more like a C++ replacement. And Elm is too domain specific and maybe a bit too simple (lacks ad-hoc polymorphism).
So maybe a general purpose Elm like language with ad-hoc polymorphism, but not as complex as Purescript, with a GC that compiles to binaries and WASM with a standard code formatter and very conservative regarding new language features, just like Golang.
> Modern Haskell has diverged to such a degree that it seems to be (almost) impossible to define a common standard. Even if they would, as long as there a over 100 language extension (increasing over time) there will be developers using them. Take a look at C++20, I think it's obvious that C++ is beyond repair at this point in time, even if you wouldn't add any more language features.
I disagree. C++20 is a standard, even if it is ugly and terribly complex it is being implemented by three separate compilers. And look at Javascript. The attention given to it is starting to show, making the language neater than in the past. The task is not straightforward but the point of the article is that there is absolutely no manpower ready to do it. I think that a few dedicated people could do the work well.
I sometimes think that not enough people appreciate the tough spot that C++ was in around 2008 and just how far it has come since then. The additions via evolution to C++ have been far beyond what I would have thought possible. IMO, the 3 year release cycle is just the right pace.
Yes, I know the language has become complicated and there are still a lot of rough edges. But it's a model of change that's worth emulating.
The C++ additions surrounding move constructors, rvalue references increased my practical complexity understanding the language (although mostly grokked now). Everything else seemed the good kinds of additions; just having a new, more palatable way to express things. If you go deep in templates, some stuff might add complexity, but overall a lot of new stuff just vastly shortcuts the crazy turing complete stuff people were doing anyway
> I think what we really need is a new language that picks all the good parts from Haskell, but has a very small syntactical core. Something like Go, but purely functional.
I'll wait patiently until people start asking for more language features, like the ten thousand last times... every widely used language ends up converging towards at least C++-levels of expressiveness (Java, TypeScript, Go, Python with static types, Caml, etc... you name it) because it turns out that those features are actually needed.
I agree that they all converge on a standard set of features, but I disagree that the features are needed.
You could get everything done with Javascript's prototype system that you wanted done with classes.
You can get everything done with Go's interfaces (and a bit of boilerplate for the edge cases) that you can do with generics.
The problem is that people come to this language from other languages, and have expectations that this language is basically the same as the other language they already know (and if not, why not?). There's a constant pressure on languages to conform to a single set of "known good" conventions [0]
The unusual languages are needed because we need that diversity, but they are never going to be "mainstream" until/unless a Java dev can learn them inside 3 months without challenging any of their assumptions about programming.
[0] the classic is Erlang vs Elixir - Erlang is "weird", Elixir is "awesome"
> You could get everything done with Javascript's prototype system that you wanted done with classes.
> You can get everything done with Go's interfaces (and a bit of boilerplate for the edge cases) that you can do with generics.
by that logic why don't you just use lisp for everything ? it's been there since 1958 and you can also get everything done with it, including reimplementing yourself a Go- or Js-like DSL if you allow yourself a Racket.
The truth is, your "get everything done" actually does not include everything, because "writing less boilerplate" is not only a feature, but one of the most important ones. Boilerplate is unambiguously bad and a place where terrible bugs hide - any time you can replace it by something with much less chances of bugs, such as a language feature, you should (and I'd argue it's professional malpractice to chose not to when you have the option).
Boilerplate isn't necessarily evil. Imo, repetitive boilerplate is where the problem comes in. I.e. it's not a bad thing that every HTTP app has an almost-the-same way to start the HTTP server. It is a bad thing when you're writing almost the same code but with different types 37 times.
There's a seemingly inevitable tradeoff between complexity and bugs. Low complexity tends to lead to repetitive, simple, avoidable bugs. High complexity leads to unique, hard to reason about bugs.
I find the preference for simple vs complex code has to do with what kind of bugs programmers want to troubleshoot. Some prefer simple and repetitive bugs, others prefer fewer, more difficult bugs.
On that note, I remember when Borland released BIDS 1.0 and was doing with the preprocessor what Go, reinvented almost 20 years later.
Or using Eclipse EMF to read UML interchange files generated from Rational Rose and generate the boilerplate for Java applications, before generics and compiler plugins were a standard Java feature.
When languages aren't feature rich, someone will eventually start writing that boilerplate, hence why //go:generate exists, despite the fact that Go people telling writing boilerplate is not a problem.
disclaimer: I'm a haskell user who has worked professionally with F# for 3 years
I don't think something like native F# would fit Haskell's niche: Haskell's type system is a lot more complete (and complex, by virtue of cruft and necessity) than F#'s. F# also has a lot of object oriented stuff which Haskell doesn't have (by design, i'd say). Maybe purescript or idris if they had more mature native compilation targets would come closer, but even those are strict (while Haskell is lazy) and laziness by default is a big thing that sets Haskell apart from virtually any other language in use.
F# is too restrictive and poor in terms of types and syntax. OCaml would make a better option as the Haskell "successor". Though, personally I don't think it will ever happen.
Maybe what the standardization committee should do, make some of these extensions (the often used and less controversial ones) into the language standard?
I concur. This post was excellent, but is now highly outdated. The Haskell Foundation is doing some amazing work in coordinating the development of Haskell, its ecosystem and its tooling. We don’t have Haskell202* yet, but only because there are more important things to do; if the Haskell Foundation decided to prioritise it, I feel confident that it would get done.
To be fair, what was called Haskell prime and ended up being I guess Haskell 2010 also took forever.
Haskell users have strong opinions about language syntax- I suppose moreso than your averaged user base. It may take a generation as Doug crockford says for those options to die and retire so new ones can come take their place. Looks like that still holds.
If you're interested in Haskell and are doing web dev, check out IHP, Haskell's version of Laravel/Rails/Django: https://ihp.digitallyinduced.com/ (Disclaimer: I'm founder of the company that makes IHP)