At Channable, we have had a great experience introducing Haskell for our infrastructure projects. We have written a few blog posts about this which you can find on our tech blog[1].
- Jobmachine, an advanced job-scheduling system with dynamic dependency resolution[2]
- Vaultenv, a small open-source tool to get secrets from Hashicorp vault[3][4]
- alfred-margaret, a blazingly-fast Aho-Corasick implementation written in Haskell[5][6]
- Sharkmachine, our in-house replacement for Apache Spark[7]
Yes, you are correct. We have not open-sourced Jobmachine yet, since it is still pretty specific for our workload, but I hope we can generalize and open-source it in the future.
Don't wait to fix it. If you want to release it ask for it to be released. Doing anything else is being fake-open-source; the real reason you don't want to release it is because of some value you think it has, not that it would actively hurt other people through its design (how...?).
It's amazing it's done in Haskell. I never knew this. I used it couple of times to convert docs. I also installed it many times with the gem bundler system for my rails, middleman app projects.
when you think about it, not toooo surprising. Haskell's undeniable killer app is parsing and compilation, so pandoc was pretty much a project destined for Haskell if I ever saw one :)
I work for a small data science consulting company whose major components of a machine learning pipeline were written in haskell. The company got bought by a large corporate and shortly after, all the haskell developers left, leaving a handful of people (including myself) who didn't know how to use or maintain the major components of a multi million dollar acquisition. It is in the process of being scrapped and replaced with a more typical software stack.
Exactly. The value is in the mental model the development team has accrued through working on the code, not the code itself.[1][2] If you lose the code but retain the development team then the code can be rewritten. Lose the team but keep the code, as in this case, and you're left with a bunch of software that no one really understands how to maintain, much less improve on, without working at cross-purposes to the original design. For a new team to develop the same degree of experience and familiarity with the codebase as the original team is only marginally less work than reimplementing it from scratch. At that point the language it's written is the least of your issues.
No doubt. Just wanted to share my experience, and the potential risks of starting a large project (or acquiring one) in a language most 'coders' aren't familiar with :o
You can’t just train any software developer to code in Haskell. It’s not an easy language to learn and a lot of programmers don’t want to learn it. And even if they managed to train up the current staff, they will either have to continuously hire Haskell programmers or continuously hire people who don’t know Haskell and hope they’re able to learn it.
To be fair, purportedly "easy" languages such as Java aren't actually easy. True, a lot of people can write (or copy paste from online articles) crappy Java code full of bugs and performance issues and nobody will notice since this low quality seems to be some kind of industry standard. But there aren't that many good Java developers either.
A similar argument used to be made about PHP: anyone can use it. To write poor software, that is.
As for Haskell: it's different enough to Java-like and C-like languages that it's difficult to wrap your mind about it if you come from those languages. But if you start fresh, it's not that hard. Some years ago someone here on HN posted pretty good results when teaching Haskell to kids. Young kids pick it up surprisingly fast. It's not inherently difficult, and in fact some of its concepts may be easier to grasp than traditional imperative languages. (And no, you don't need to understand category theory at all in order to program with Haskell).
As for Haskell ... if you start fresh, it's not that hard.
I'm going to respectfully disagree with that.
I do understand the point you're making. In fact, my own experience of having taught beginners without preconceptions to program is consistent with that point.
However, the "scale" of a language (including all the strange edge cases) is very relevant for production use and particularly maintenance. Even if you stick to a core of widely understood language features and libraries yourself, you might still have to maintain code written by someone else that uses more obscure features or complicated interactions between features.
For Haskell, that "scale" is usually determined in practice by GHC plus whatever language extensions anyone has turned on plus whatever libraries they've found from Hackage or elsewhere. Those language extensions are numerous, and they can not only add new language features but also change existing code to behave in different and potentially unexpected ways. As a platform for research and development of programming language concepts, that is a benefit. As a practical programming language for production use, it is a huge liability.
The scale of Java is also insane. The standard library is huge. The commonly leveraged frameworks, also huge. And the abstraction...my God, the unnecessary abstraction.
How many people, offhand, know the difference between a Runnable, Callable, Function, Consumer, and Supplier? I include all of them because literally the only meaningful difference between them is whether they take an argument or not (Function and Consumer do), and whether they return an argument or not (Callable, Function, and Supplier do).
How many people know the difference between a Future, a CompletableFuture, a RunnableFuture, a ScheduledFuture, a ScheduledRunnableFuture, and a FutureTask? I've done async code in Java; I still can't keep them straight.
Future is something that will eventually produce a value.
CompletableFuture is a Future that you can register a callback on for when it completes.
RunnableFuture I'm not completely sure on, but I'd guess it's a Future that will complete but won't produce a value (basically a Future<Void>).
ScheduledFuture is a Future that you can specify when it should run in the future.
ScheduleRunnableFuture is a RunnableFuture that has a defined time it should start running.
FutureTask is a RunnableFuture you can cancel. OK, so I cheated on this one, I didn't actually know what it was and had to look it up.
Edit: I looked up RunnableFuture and I was half right. It's something that's both a Runnable and a Future, so it has a run() method that causes the future to be evaluated but doesn't return its result at that time. It actually seems pretty niche and probably only useful if you already have some API that's expecting a Runnable, otherwise it's exactly equivalent to calling get() on a Future then ignoring the returned value.
Cool; next question - you have a library that returns Futures. You have another library that takes CompletableFutures. How do you feed the output of the first into the input of the second?
Also, as a note, FutureTask is the only implemented class out of those; the others are all interfaces.
Java is complex as well, it has a 800 pages manual, and that's a language only and no libraries. It has a complex memory model, quirks like pointer-only parametricity, quirks to bypass quirks like autopromotion to help with pointer only parametricity.
Oh, and java have pretty much obscure extensions as well. Ever heard of metaprogramming via Java Reflection?
Haskell without extensions is 300 pages only and way more simple. And extensions are not that numerous and often intersecting.
Programming languages (at least in the context being discussed) are just a means to model a problem domain. Some people find it easier to model domains in strongly typed functional languages but at a much larger percentage do not. Let's for argument's sake say it's 1% of all programmers. That is still a huge number of people though.
It could be argued that coming up with the original model was easier done in Haskell by the expert Haskell developers. Translating it to another language is more or less mechanical task. Then the maintenance and further development can happen in a more commonly known language.
In other words languages like Haskell, Lisp etc. are precisely good for modeling the problem and its solution, so it can make sense to use them for that even if later development is best done translated into a simpler-to-use language.
"It’s not an easy language to learn" - pure opinion.
"and a lot of programmers don’t want to learn it" - also opinion, but I'd be very curious to also know how the quality of those who do want to learn it compare to those who don't.
There's always a ramp-up period for new employees. While it's hard to learn Haskell completely on your own, it's not that hard to learn Haskell if you join a team of experienced Haskell developers. Once they build up a competent team, absorbing new team members really wouldn't be that hard. The only problem here is really that the entire team left -- that would've been a pretty big problem for any complex software system regardless of the language it was written in.
Agreed 100%. There’s so much domain knowledge in a lot of systems that run in production for a couple of years that the disappearance of the entire team means basically a full rewrite.
The new ownership probably had no idea what they actually bought. I think to be fair, whilst it may have been cheaper to hire new devs than rewrite everything, it would have taken a while to learn and become proficient enough to use and properly maintain the existing codebase properly.
Progress to a standstill? Making code that solves problems, so that money can be made, is the goal of any software house that wants to ever have a positive cash flow. If it were easier or cheaper to hire for and write code in Haskell, which would make this goal easier to achieve, then it would already be used, and this the case in some domains. Beyond those specific domains, not many companies have the spare resources to donate to progressing the ideas/ideals of software development, unless there's a real, monetary, ROI. For many houses, there is none, at the moment.
It's always cheaper/easier to optimize in the environment one is currently in.
I bet you the new stack will have more bugs and be significantly more complex and harder to maintain. But you will find tons and tons of developers willing to continuously add technical debt to it.
While this is certainly a legitimate concern, we should also consider how much of that multi-million dollar value derived from the use of Haskell up to that point. Put another way, had a "more typical software stack" been used originally, would the acquired business still have achieved the same things and been as attractive for acquisition?
Why don't they hire Haskell developers to replace the ones who are leaving? If your company's Java developers were leaving, they'd be ridiculed for deciding to rewrite the codebase. Is it really that hard to hire Haskell developers?
Just curious, what was the reason that Haskell developer left?
I know 1 company where this happened, but there Haskell developers left because management decided to move to python (without them even knowing its under consideration).
I've seen this happen with Perl and Ruby (both replaced with Python). Being able to replace workers is not an insignificant business risk. A small company outside of a major tech hub just can't support the development of software in nonstandard languages. I love Haskell, but I couldn't tell my boss that we should invest time in learning yet another technology to train people in just because its my favorite language.
There is a growing number of stories in the wild of companies who were burned for using Haskell. Common patterns of struggle are emerging. You aren't reading about them because people aren't eager to share their failures with the world, just yet. Proceed with caution, especially in the startup realm.
As a counterpoint - at CircuitHub, we migrated from NodeJS / Angular to Haskell / Elm and couldn't be happier.
I think a core reason for our success is that we built our team from experienced developers that had built large applications in other languages. Then arrived at Haskell as a better solution.
I have heard some negative experiences that I would attribute to a few different factors.
1. Lack of Haskell experience in the early team.
2. Lack of experience building large real-world applications (too academic)
3. The startup/group didn't achieve product-market fit, and Haskell was scapegoated.
None of these problems are Haskell specific, just run of the mill team issues.
How common is it for the same person to have both strong Haskell experience and experience building large real-world applications?
I’ve tried to find a way to use Haskell (lacking strong experience there, but with lots of large app experience), and I’ve not managed to find a situation where pulling the trigger makes sense because of the risk of getting “stuck” with a poor path out.
> How common is it for the same person to have both strong Haskell experience and experience building large real-world applications?
I would conjecture that it is more common than what you’d expect from random chance. In my case, I picked up Haskell only after building large systems in C++, Objective C, Lisp, and Python. The draw was that Haskell let me express the kind of system invariants that make it possible to reason about a large codebase.
Since then I’ve written production Haskell in three different companies, none of which appear on this list.
Maybe try contributing to a large Haskell codebase first to get a feel for what Haskell is like in in-the-large and gain some comfort.
I'll add this problem is not at all Haskell specific. If you put an experienced Java developer to work architecting a large Python application where they have no prior Python experience you are going to experience similar problems.
I'd say the problem is perhaps a bit more acute with Haskell as the paradigm is likely more different to the prior language.
So if possible get at least one person on your team that has experience with a large Haskell app and pair them up with other devs.
In tech world languages are like a religion. Their choice does not really have to make sense. Hence unless it is 100% total proven failure the affiliates will try any means to protect/advocate/spread whatever language they like.
We definitely could have built our product using more mainstream languages.
I wouldn't, however, say we required a team of wizards, just good developers that prefer to work in Haskell if possible.
True but run of the mill languages like this always tend to culminate in codebases that are hard to maintain and necessitates an eventual rewrite due to accumulation of complexity.
Haskell is hard to learn and hard to find developers for, but the trade off is incredible safety and a type system that promotes good design and easy refactoring of inevitable design flaws.
To achieve such a thing with other languages you need a highly disciplined team/culture and you need lots of time (meaning less hard deadlines and time crunches) and willingness to invest time into refactoring.
> True but run of the mill languages like this always tend to culminate in codebases that are hard to maintain and necessitates an eventual rewrite due to accumulation of complexity.
I'm reluctant to believe that Haskell magically protects you from that, but let's suppose it was true. What if my run-of-the-mill gang can rewrite the project three times over before your wizards have congregated to sing their first incantation?
> Haskell is hard to learn and hard to find developers for, but the trade off is incredible safety and a type system that promotes good design and easy refactoring of inevitable design flaws.
Again, I'm reluctant to buy into that. Even if that was true, unless you're writing Haskell in a vacuum, you're going to have to interface with various other horrible pieces of technology that will throw a wrench into your beautiful pure design.
Dealing with the ugly bits while maintaining composure is what makes the difference between a really good engineer and somebody who just wants to program. That quality is invaluable, but you're likely not going to develop it by programming in a language that you enjoy.
>I'm reluctant to believe that Haskell magically protects you from that
i can only show you the door you have to walk through it.
>What if my run-of-the-mill gang can rewrite the project three times over before your wizards have congregated to sing their first incantation?
The 3rd rewrite of your nodejs app still has technical debt. It still has flaws and still is buggy. Every time you redo it, you repeat the same mistakes over and over and over again never knowing how to make things better. You are doomed to participate on an endless cycle of rewrites as people of every generation reinvent the wheel with a new framework and new mistakes never converging on a better solution.
It's a myth that Haskell is slower. The speed I would say is the same because Haskell you would require significantly less testing and validation.
>Even if that was true, unless you're writing Haskell in a vacuum, you're going to have to interface with various other horrible pieces of technology that will throw a wrench into your beautiful pure design.
You do that anyway. At least keep one section of your stack safe and nice. Haskell.
>Dealing with the ugly bits while maintaining composure is what makes the difference between a really good engineer and somebody who just wants to program. That quality is invaluable, but you're likely not going to develop it by programming in a language that you enjoy.
Haskell is about safety and good design. If these two things are not critical to your program, then you shouldn't go the way of Haskell. If it is, Haskell is one of the best technologies to meet that requirement while not costing too much in performance / speed of development.
If Haskell has a critical flaw it's the learning curve. But that's a one time deal. Once you get past the curve you're good. Also don't call us wizards. We're not... Haskell isn't that hard. Anyone can learn it, this isn't like quantum physics. Becoming an expert database SQL ninja admin on postgresql is probably just as hard as becoming one on haskell. haskell like sql is just a bit challenging because it's expression based as opposed to imperative like python.
>Are you seriously suggesting that code written in Haskell cannot have bugs, flaws and technical debt?
No way. Not at all. I am suggesting that Haskell code will have significantly less bugs and less technical debt not none. I am not making a single outlandish claim.
>Am I to understand that people writing in JS cannot learn from mistakes, but people writing in Haskell can?
Yeah. Every couple years people who write JS come up with new garbage frameworks that don't really move the needle forward. React, angular, vue, jquery.... different flavors of the same issue while fixing old problems and creating new ones. Of course their's slight progress forward with things like type script but overall I see the same mistakes being repeated every generation. History repeats itself is a popular saying because there are just as many people who don't learn as there are people who do.
>Haskell is a cool language, but you are not helping its image by such outlandish claims.
Maybe you should understand my claim before calling it outlandish. Significantly less bugs and less technical debt is a real thing, but nowhere did I claim ZERO. You still need unit tests and you still need to think about your design.
Perhaps it's my fault. My comments deliver a perception about haskell that is false. I'll think about it, but in no way did I intend to imply anything outlandish about haskell.
> Every couple years people who write JS come up with new garbage frameworks that don't really move the needle forward. React, angular, vue, jquery.... different flavors of the same issue while fixing old problems and creating new ones.
People needed to figure out how to turn HTML into a somewhat usable application platform while it is evolving. The DOM of 2019 is not the DOM of 2009. Javascript ES6+ is far different from ES3. It's chaotic, but how could it not be?
The other day, someone posted a link on writing Haskell for the web frontend. Guess what, people were reinventing things over and over there too, it's just that nobody really took notice of it.
Yeah your presumption is absolutely correct. I love seeing you use loaded presumptions to try to communicate with me.
I presume that after I say this to you you’re going to stop communicating with me because shoving random presumptions up someone’s mouth isn’t a polite and civil way to communicate. Prove me wrong.
Fair enough. But you have are some fairly strong (bordering on inflammatory) criticism of JS frameworks and the people developing them - but without any specifics which would allow one to counter you (or agree with you for that matter).
It just "garbage" and "mistakes" and "people who don't learn" - how do anyone argue against that?
You can argue against the generalization if it’s wrong. If it’s not wrong your best bet is to stand by why the framework is good despite the correctness of the generalization.
It’s a cheap but affective method to use details to attack generalizations. However the insidious thing about generalizations is that details can be dismissed as noise irrelevant to the main point. A real argument against a generalization is another generalization, with supporting evidence.
> The 3rd rewrite of your nodejs app still has technical debt. It still has flaws and still is buggy. Every time you redo it, you repeat the same mistakes over and over and over again never knowing how to make things better.
Oh really? Well that's good news too, because now I can just save myself those rewrites, because they're pointless. That's a 3x improvement right there.
> It's a myth that Haskell is slower. The speed I would say is the same because Haskell you would require significantly less testing and validation.
If you have wizards, that is.
> Haskell is about safety and good design. If these two things are not critical to your program, then you shouldn't go the way of Haskell.
They certainly aren't critical to your run-of-the-mill NodeJS/Angular project which, I must remind, is the alternative that we are discussing here.
> If Haskell has a critical flaw it's the learning curve. But that's a one time deal.
No, it's a "one time per hire" deal.
> Also don't call us wizards. We're not... Haskell isn't that hard.
I'm certainly not calling all Haskell programmers wizards, I'm referring to that "team of experienced developers that had built large applications in other languages (and then arrived at Haskell as a better solution)" that the original commenter saw as a requirement for success.
Of course it's not impossible to assemble such a team for a run-of-the-mill project. It's just impractical.
> Becoming an expert database SQL ninja admin on postgresql is probably just as hard as becoming one on haskell.
See, that's another kind of expert that I definitely don't want to need on the team. I want people who have a basic understanding of SQL, with a reluctance to learn the ins and outs of it. That'll dramatically lower the chances of them trying to be smart with SQL.
I'd just like to call attention to this. There is no wizardry to learning (basic) Haskell very well, i.e. to such a degree that using an Elm-like library would not be an obstacle to getting the job done.
You may not ever learn advanced Category Theory, but that -- contrary to popular belief -- is not actually necessary. You may end up using some libraries that use Category Theory at an advanced level (lens), but at absolute worst we're talking learning to parse compiler error messages that are about 1-5% of what a C++ compiler will spit out at you.
>Oh really? Well that's good news too, because now I can just save myself those rewrites, because they're pointless. That's a 3x improvement right there.
No dude don't even write it because likely it will be garbage. If you truly believe that nodejs apps don't need to be rewritten go to Uber. They never rewrote their entire nodejs code base in Golang.
>If you have wizards, that is.
Haskell isn't all wizards. It's just regular people who learned something different.
>No, it's a "one time per hire" deal.
Same with almost every other language that isn't popular yet. Rust and golang and kotlin and swift all went through this. The goal of any language is to become popular enough to get past this.
>I'm certainly not calling all Haskell programmers wizards
Then what is the big deal. If we aren't wizards then it's easy to learn. Programmers learn new languages all the time. Learning Haskell is just slightly more challenging and not a huge drain on productivity. Spend a couple more months training new developers in exchange for a 90% reduction in bugs and much better design.
>See, that's another kind of expert that I definitely don't want to need on the team. I want people who have a basic understanding of SQL, with a reluctance to learn the ins and outs of it. That'll dramatically lower the chances of them trying to be smart with SQL.
Eventually for certain queries you will have to get clever and write queries to optimize. Additionally to serve certain architectures you have to know a lot about the inner workings of the database and how to manipulate the api to get the performance needed at the lower level. An expert has no trouble with this and is an asset. This isn't about getting clever or doing tricky things with syntax just to be clever... this is about inevitability of the fact that a client will want to ask a question to a database that has grown so complex it is not straightforward to answer his question in a performant way. This is extremely common even for your run of the mill web app company.
But that's besides the point. I'm comparing haskell to SQL because it's a similar learning curve. Both are expression based languages. In fact I would argue that Haskell is EASIER then SQL due to the type checking.
Learn the language if you really want to understand our perspective. I use to be in that camp of why learn a freaking language when it's barely used, but that changed once I learned haskell.
There is no "big deal". You're taking my facetious use of the word "wizard" the wrong way.
> Same with almost every other language that isn't popular yet. Rust and golang and kotlin and swift all went through this.
If Haskell already was popular, it would be an entirely different argument. Then we can talk about the merits of the language/platform versus the alternatives. Right now you're trying to sell me this exotic language used by exotic programmers who have strong opinions on design. From a business point of view, those are alarm bells. That's what you need to at least recognize, even though you disagree.
> Learning Haskell is just slightly more challenging and not a huge drain on productivity. Spend a couple more months training new developers in exchange for a 90% reduction in bugs and much better design.
This is what you believe and take for granted in your argument. I'm sure you're sincere about that, but remember, I'm not buying all those beliefs wholesale. Haskell has been around for thirty years, if it really makes for such vast increases in its productivity, why aren't those Haskell programmers dominating software development?
> This just tells me you're someone with little experience.
At least consider the possibility that there's some insight there that you don't quite grasp yet.
> Learn the language if you really want to understand our perspective.
"Buy the product in order to see why it's so great!" would be a terrible sales pitch, if you catch my drift.
>There is no "big deal". You're taking my facetious use of the word "wizard" the wrong way
And your taking my statement the wrong way. If there really is no big deal then there is really no big deal in me telling you and you actually learning it.
>If Haskell already was popular, it would be an entirely different argument.
If we are here to debate about popularity, then you win buddy. Haskell is not popular. That much is obvious. Every language starts somewhere and I'm here to promote why it should be popular. If you can't buy into that then well there's no point in talking. I get your point. Haskell is exotic and niche. But this is already stupendously obvious so why bring it up. If you don't want to use it for popularity reasons that's a valid point. But that does not discount the technical merits that lend positive credence to why you should use it. 90 percent less bugs then JavaScript is a technical feature that has profound impact on business as does 90 percent less developers.
> if it really makes for such vast increases in its productivity, why aren't those Haskell programmers dominating software development?
JavaScript was a language designed in a week and is largely universally considered to be a terrible language. Why does it dominate the software ecosystem? Because of circumstance and ease of adoption, that's it. Adoption rate isn't an accurate metric on productivity of a language. In fact these studies on productivity have been done before. The language that won was smalltalk.
>At least consider the possibility that there's some insight there that you don't quite grasp yet.
Why don't you tell me what your thinking rather then ask me to consider something that exists only in your mind.
>"Buy the product in order to see why it's so great!" would be a terrible sales pitch, if you catch my drift.
I do catch your drift. And you're right. Unfortunately my arguments don't seem to away you... If arguments don't away you than trying it is logically the only way left. But guess what free trial! Life time access. If you don't like it or if you like it, it's still yours, free!
Also, I want to say that I edited my convo to take out the fact that I thought your statement showed inexperience but you still ended up seeing it. That’s my fault and I apologize. I don’t know how much experience you have but that’s not a fair judgement to make or a civil thing to say to someone. It’s also unrelated to the topic at hand, so a faux pa on my part.
You can have monads in any language. If you have a functor you have a monad. If you have a type that wraps or encodes another type in a lossless or lossy way you have a functor. Therefore a functor exists in any language with compound types therefore every language that has compound types has monads.
The difference is Haskell makes these concepts explicit.
You have to implement the methods but things like associativity and the existence of identity are not enforced.
Additionally all IO functions in haskell are monads with a return type that is a functor called IO that can contain another type or nothing. You cannot print something to console without invoking a monad in haskell. The clever thing about the IO functor type is that it can only be instantiated by a true IO function that touches some external thing, there is no other way to instantiate this type.
So for example the Instantiated type IO(int) cannot exist unless someone called a function that receives integers from a socket. And to extract the int from the functor you have to use the monadic bind operator.
I see. Thanks. So the library-interface named "monad" includes the special machinery for programming monads. Libraries written in other languages could provide something similar, I assume.
Yeah. There's nothing special, it's purely a library which you can reimplement yourself in haskell or in other languages.
The only thing special about it is the IO thing I mentioned which is an intrinsic part of the language.
I know you mentioned javascript earlier, just know that while javascript CAN technically have monads, you kind of have to go out of your way to implement it. If you get some experience with a language that has an GADT system and really nail down the concept of a functor you'll see the full power of the monad.
I generally would avoid using a monad with languages that don't have GADT systems.
The statement seems to be about the absolute number of failures, not a proportion out a total. So I guess their comment is simply that the number of failures have increased with time...
So if the total number of Haskell projects is not also going up, then we must conjecture that people are getting worse and worse at Haskell. Occam's razor seems to apply here; it seems more likely that more people are trying Haskell for real world projects, if the statement that failures are increasing is true.
Well, presumable some people actually finish their old haskell projects and then start new ones, so it's not necessary that the total number of users is growing. The old users are also starting new projects that could fail.
That's an intruiging comment. I can understand why you can't name specific companies but it would be interesteing to hear something about these common patterns of struggle.
I've heard lazy evaluation makes performance problems a nightmare to track down: some seemingly innocent piece of code turns out to trigger evaluation. In other words, the lines of code in the diff that introduces the performance regression, can be very far from the lines that do the heavy lifting, and both can be far from the line that actually needs to be changed to fix the problem.
One flip side of this is when undefined behavior in one library invalidates critical assumptions underlying the correctness of another, and tracking it down is a nightmare.
I’d much rather, in general, get predictable and understandable semantics and have to struggle for performance than get predictable and understandable performance and struggle for semantics. Even more so, I’d rather use software that faced that profile of challenges. You can see when the program is slow at runtime, but you often can’t see when it’s wrong at runtime.
That would be an interesting question to answer. I know of a few rapidly growing companies using Haskell that compete directly with non-Haskell companies. We'll have to see how things play out over the next few years but that might provide some data points.
CircuitHub (a company I co-founded) and Habito (UK mortgage broker) stand out in my head as startups (in the PG sense of the word http://www.paulgraham.com/growth.html) that use primarily Haskell and have direct startup competition using more conventional stacks.
We come across tons of others, I keep meaning to write down a list.
The language is the language. I won't offer any opinions on what I would like to see
The problem is the ecosystem, tooling. Lack of frameworks/crms/cmses make it a poor choice
Bootcamps try to scale the learning process. In a bootcamp someone can go from nothing to productive/professional in a few weeks. This is not possible with haskell.
Sorry to seem dense, but which frameworks and tooling do you think it's lacking? Specific examples would help.
I ask because I don't think Haskell is particularly lacking in this regard, and it's successfully deployed in real life software, but I might be missing something.
The first line returns 3, and so does the second line. The third line returns 4.0. The fourth line fails with this error:
No instance for (Show a0)
arising from a use of ‘show_M552168474310802709512215’
The type variable ‘a0’ is ambiguous
Note: there are several potential instances:
instance Show a => Show (Const a b)
-- Defined in ‘Control.Applicative’
instance Show a => Show (ZipList a)
-- Defined in ‘Control.Applicative’
instance Show GeneralCategory -- Defined in ‘Data.Char’
...plus 106 others
In the expression:
show_M552168474310802709512215
(let e_16210 = (div 6 2) + 1.0 in e_16210)
In an equation for ‘e_155216847431080270951221555216847431080270951221516210621016210’:
e_155216847431080270951221555216847431080270951221516210621016210
= show_M552168474310802709512215
(let e_16210 = (div 6 2) + 1.0 in e_16210)
In the expression:
(let
e_155216847431080270951221555216847431080270951221516210621016210
= show_M552168474310802709512215 (let ... in e_16210)
in
e_155
That error message is annoyingly weird but is more to do with tryhaskell.org than haskell itself. Lots of programming languages which have a strict type system (eg Rust) deliberately choose not to coerce types even when a type conversion would mostly work so the developer chooses the set of types that get used.
GHC is a little better.
GHCi, version 8.4.4: http://www.haskell.org/ghc/ :? for help
Prelude> (div 6 2) + 1.0
<interactive>:1:1: error:
• Ambiguous type variable ‘a0’ arising from a use of ‘print’
prevents the constraint ‘(Show a0)’ from being solved.
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
...plus 22 others
...plus 18 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In a stmt of an interactive GHCi command: print it
This isn't about coercion, which Haskell doesn't have. These error messages arise because of Haskell's choice that numeric literals should be polymorphic values with a typeclass constraint, meaning I can make those literals evaluate to my own types by defining a few instances. The resultant headaches with error messages are just the usual ones you get when you combine this amount of ad-hoc polymorphism with global type inference.
For teaching beginners, I very much question the amount of polymorphism in Haskell, and one floated idea has been to use a custom Prelude with much less of it for teaching purposes. Alternatively, I would probably just tell students to read an error like that as "you did something wrong." I would say the same for any student faced with a Java stack-trace showing how their null value threw an exception deep inside library code.
The beginner isn't defining the instances. But the experts want the flexibility to define such instances, and that means even beginner code can involve an unhelpful amount of polymorphism. This isn't the case in Rust, where literals are near enough monomorphic.
Here, beginners are potentially being burned by the fact that "length" is polymorphic with the type:
length :: Foldable f => f a -> Int
which is not a type I want to explain to beginners. At the same time, as an expert, I want length to be polymorphic and don't want to sacrifice its polymorphism for the sake of beginners.
The Rust error messages are much better though. This program:
fn main() {
println!("{}", (6 / 2) + 1.0);
}
fails to compile with the following error message:
error[E0277]: cannot add a float to an integer
--> src/main.rs:3:28
|
3 | println!("{}", (6 / 2) + 1.0);
| ^ no implementation for `{integer} + {float}`
|
= help: the trait `std::ops::Add<{float}>` is not implemented for `{integer}`
The crucial difference to Haskell is that this program:
fn main() {
println!("{}", 3 + 1.0);
}
Also fails with substantially the same error message. Rust is consistent that you can't add integers to floats. Haskell's looseness around numeric literals means that it isn't.
Mind you, Rust does have that kind of looseness within the integers, so this:
That's surprising since it's fairly straightforward.
The type of `3` gets inferred as `Num a => a` because there's nothing to constrain it further.
The type of `div 6 2` gets inferred as `Integral a => a` because the type of `div` is `Integral a => a -> a -> a`.
The type of `3 + 1.0` gets inferred as `Fractional a => a` because of the decimal point.
Then the same thing happens in the last statement so the type of the subexpression `(div 6 2)` (still) gets inferred to `Integral a => a` and the type of `1.0` (still) gets inferred to `Fractional a => a` because of the decimal point.
So at that point you have an expression that's trying to add something constrained to being a whole number to something constrained to being a fractional number and that is ill typed because there is no type you could choose for the overall expression that would meet both sets of constraints.
Edit: When I first replied there was text at the bottom of the message saying that no one could explain why this happens. My comment was addressing that portion of the original message. The behavior itself is not surprising for the same reasons.
Don't get me wrong here, I get what you're saying, but: In practice a beginner would figure out you can't just 'silently' add Integrals and Fractionals by checking the types with the ":t" command
Ambiguous type variable ‘a0’ arising from a use of ‘print’
prevents the constraint ‘(Show a0)’ from being solved.
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
...plus 22 others
...plus 18 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
In a stmt of an interactive GHCi command: print it
If everything is subjective and we don't bring counter arguments to one's arguments, then science cannot go on. In programming, we need to know if objectively one programming language is better than the others, so as that we use it to our benefit.
I don't see any claim in that article about everything being subjective, it's very specifically about programming languages.
I would argue that programming languages are subjective. There are many different equally viable ways to model the world and programmers should pick the one that aligns with how their brain works.
I'm not convinced it's possible to objectively rank programming languages from best to worse. They are not fundamental properties of the universe simply mental models devised by humans for humans.
Can we? Expectations around what a language can do are dymanic.
I saw something really cool on the weekend. PHP on the client side as a compiled wasm. This allows someone to go severless and run a cms in the client.
That's a new use for an existing language.. is it suitable for everything? Not until it is.
> need to know if objectively one programming language is better
Better for what, for whom? Every programming problem is basically a unique problem of its own -- else the solution would already exist as source-code. There's no need to re-program the wheel.
Therefore the generic question of "what programming language is objectively better" does not make much sense, unless we qualify the question with: better for what, better for whom.
That probably means Haskell is becoming more popular. Most software projects and businesses, after all, fail.
I wouldn't advice against Haskell. But I would advice against having a business with more than one non-boring component. And usually that non-boring component should be the solution to the client problem, not the tech stack used to implement it.
If you start a business in a language stack none of the devs have done large scale production projects, you are basically begging for a world of trouble. If the devs are familiar with Haskell, I don't see any problem with choosing it, if it matches the problem domain. I wouldn't choose it for example for frontend development (although I suppose you can get it compiling there) or things where C, C++ or Fortran still have a strong legitimate foothold.
I considered Hasura but went with postgraphile (https://github.com/graphile/postgraphile) because it's written in JavaScript with a plugin architecture, meaning I can easily add my own plugins into the system down the road. Creating a JavaScript plugin sounds much less daunting that looking into a mature Haskell codebase.
Hey, have you seen the preview docs of hasura actions? It has a small example of integrating python (or for that matter, any language) for custom mutations.
I also came to comment on Hasura. Without having looked into the code I can’t really comment on the quality, but certainly from the outside it’s rock solid.
For me, one of the biggest non-starters is a slow compiler, or rather a compiler that doesn't scale well. When people talk about how smart their type system or their compiler is, it immediately rings alarm bells for me.
This is one of the things that you may only learn the hard way, as your project grows in complexity. Nobody advertises how slow their compiler is.
So, my question is, how does GHC fare these days? How does it treat people that switched from a dynamic language, who are used to quick iteration?
I think quick iteration and feedback is one of Haskell's strong points :)
It has been argued before, in a fascinating but admittedly flawed experiment for the Naval Surface Warfare Center (US Navy) [1], that Haskell is a great prototyping language. This experiment is flawed for multiple reasons which the authors readily admit (e.g. the results from all contestants were self-reported, the requirements were vague [2], no code was actually run by the panel of judges, etc), but it's still tremendously interesting. It's also amusing that the judges couldn't believe the Haskell program was a working and complete implementation of the system, and thought it was either pseudocode or "too clever" for its own good (because of the use of higher-order functions)!
[2] though one could argue vague requirements are actually another point in favor of Haskell as a rapid prototyping language. It's often argued -- mistakenly -- that languages with static typing are not good for exploratory coding, which this experiment tends to show not to be true.
For quick iterations, you have ghci. You just edit your files, type :r and it will recompile only necessary files, which is really quick (and I miss it in most other REPLs). Similar with incremental compilation. But if you need to compile huge project always from scratch, of course, you will suffer.
There have been work on making haskell to have deterministic build to speed up compile time, and compare to scala, I find it way faster (in my current company, we use scala). But note that if you start using stuff like template haskell, your compilation will slow down.
To give you a single data point, our Haskell code base at ITProTV is about 50,000 lines of code. Reloading the project after a change in GHCi takes slightly less than one second. We haven't spent any significant effort on speeding up compile speeds, for what it's worth. It's fast enough.
It doesn't feel slow to me (compared to for example C++ compilation) and you can iterate quickly using cabal repl (:r) or ghcid[1] which both support partial recompilation of changed files.
Quick iteration means quick feedback and that is a major success-factor for software projects I believe. The purpose of compiler is to give you feedback about what you're doing wrong, but if that feedback is slow then it loses much of its value. Goal is to guide the programmer, not stop them.
While there are benefits of learning Haskell as a developer. I am curious about the professional benefits versus the time and effort required to master the language to the extent that you are employable and command a good salary compared to just focusing on mainstream languages where you probably have a lot more competition but also a lot more opportunities.
I have been looking around for Haskell jobs for a while because I would love to program in Haskell professionally, and what I've noticed that there are very few opportunities and the salaries are quite low.
You can expect to make much more as a Scala programmer, for instance.
The effort of learning Scala vs Haskell as at a professional level would be more or less equal.
To be fair, most asked questions about Haskell that people always have is if Haskell is so good and not just purely for academics then where is Haskell used in industry? Or is there really huge and complex software projects written in Haskell?
I don't know what it is, but it does satisfy an itch. I took one class that used Haskell and ever since then I find myself missing it. I think something about writing in the functional mindset makes it easy to write "elegant" solutions.
Could it be because learning Haskell was such a major effort for them that they now don't want that to go to waste?
Learning Haskell (well) is a big investment. If you make that investment, of course you are going to argue that now we should reap the benefits of that investment.
It makes sense from the point of someone who has already made the investment of learning Haskell. But, choosing Haskell for a project means that other current and future programmers must make that same investment in leaning Haskell too, rather than learning something else perhaps. Or using what they already know well.
As someone who has hired many developers at a large Investment bank, I always found that people that knew Haskell or some other functional programming language tended to be far more productive in standard OO languages. I know of many other technical leads and hiring managers that look at Haskell as a market signal. As someone who does code in F# and Haskell in my spare time, I don't expect to get job using either of these languages, but knowing these languages got me a foot in the door to do some of the most interesting work I have ever had (many years ago). From those in the Haskell community that I do interact with, most people do not expect to code in Haskell for their day jobs, and most of them would continue writing Haskell code outside of work regardless of whether Haskell becomes a commercial success or not. For me, Haskell is one of those languages that is just worth knowing, simply because it gives you a different perspective on the world and a new set of mental tools. If you haven't as yet played with a strict functional language, then you really should give it a try.Not because you expect to use it at work, rather because learning new things is fun and it will make you better at your job anyway as a side effect. If the logic you used in your argument holds, then we should really be coding in assembler.
I've found the exact opposite. People i've worked with who are keen on Haskell have tended to be keen on building castles of unnecessary abstraction. People i've worked with who are not keen on Haskell are less so.
(Giuseppe, if you're reading this, you're the one exception!)
This sunk cost fallacy argument is easy to apply to many languages. Of the ones for which I've approached expert-level knowledge, C++ stands out as the one with the biggest sunk cost for the least gain. But let me tell you about my experience over the past couple years with OCaml, and why I think experts of Haskell, ML, and related languages are motivated by epiphany rather than sunk cost.
First, my CS background. I started programming in 1991, and have used dozens of languages major and minor over that time. At one time or another, I developed especially deep knowledge of the following: C, Perl, PostScript, Python, C++, and PHP. Functional languages always hovered at the edge of my interest, but never seemed practical enough to apply to the sorts of systems programming I love.
In 2017 I decided to spend some time broadening my understanding of language concepts, and made a list of languages to learn more about: OCaml, Julia, Clojure, Scala, Scheme, Haskell, Rust, Erlang, Go, Swift, and Kotlin. Learning OCaml ended up being such a transformative experience that I use it almost exclusively now. As an aside, I must say that it wasn't easy; it took the better part of a year to acquire the knowledge and experience necessary to feel productive.
Why is OCaml (and presumably Haskell) so good? The resulting programs feel like beautiful self-consistent crystalline structures rather than balls of mud. Furthermore, the powerful type system allows refactoring from one crystalline structure to another such that inconsistent hybrid crystals rarely occur. This is a much different experience from reshaping a ball of mud. The routine elegance and safety of these program representations aid in discovering the essences of solutions, and I have written programs I never would have discovered in other languages.
Killer features:
- The powerful type system clarifies design, aids refactoring.
- The module system (in combination with generics) enables truly modular design.
- Effectless computation (pure functions, immutable data) simplifies reasoning about state.
I have some complaints about OCaml (and every other language I know), but it stands out as by far the most fulfilling to use. Going forward I will prefer to spend my programming time using languages more like OCaml, Haskell, Rust, etc. than those I used for the first 25 years.
It's not about "sunk cost". It's about making a new investment. How much would it cost to train all your programmers to be productive Haskell programmers?
Is it a worthwhile investment for your company? I'm not saying it isn't but that it is a big new investment if you're planning to make that transformation. Will it pay itself back in time? Maybe, maybe not. Or are there some other investments which would seem to have a bigger and less risky rate of return?
> How much would it cost to train all your programmers to be productive Haskell programmers?
Dunno about Haskell, but OCaml is way more simple than C++ or even Java. OCaml manual is 100 pages on informal tutorial + 100 pages of formal language definition. Another 200 pages are dedicated to runtime and tooling, and 400 more for the whole standard library.
With Java, the language manual itself is 800 pages, and that's without the library or runtime.
I don’t know Haskell so this is an abstract comment, but: effort put in is only a multiplier. If you put a lot of effort into something you despise, or that does not do the job, you will not be advocating it.
Thus, even if it is the case that it requires major effort, but people love its power, your word of caution is not really undermining the argument that it is a useful/powerful/enjoyable tool.
My guess it is actually more about silver bullet syndrome. Haskell seems great on the surface when you don't need to deal with state, order, memory constraints, memory layout etc. and can just focus on data flow problems.
I think people want programming in general to have that sort of simplicity, but data flow programming is already where focus can be on transforming data without the complexities of most real world programs.
I think there is a lot of desire to try to make Haskell work in all situations instead of what it is best at.
Let's talk in things that are more tangible. Haskell attempts to answer the question: "In the set of all possible programs that can be written to solve a certain problem domain how do I find the program that has the best modularity, best design and best safety?"
You would think that to answer the question above you would need a really expressive language. Haskell is a language that is actually less expressive and more restrictive than mainstream programming languages. You can be much more expressive in JAVA, C, C++, python, javascript and python then you can in haskell. For one you can mutate variables and re-assign them in mainstream languages and you can also have Loops. These things don't exist in Haskell.
Sounds really bad right? In actuality this is what makes haskell so powerful. Haskell is restricting the programmer to only be able to create a program that is much, much closer to answering the question above. The best design and the best modularity sort of exist has nebulous and instinctive concepts in most programmers. With haskell this concept comes closer to concreteness because Haskell simply doesn't allow you to write certain programs that are poorly designed or incorrect.
My first experience writing a non trivial haskell program was astonishing. Normally I program a little and test a little, then continuously add complexity to my programs through this iterative process of coding a little and testing a little.
With haskell I coded the entire program. Once it compiled it worked. No testing needed. I asked myself what was it that allowed me to do this in haskell? The answer was that it was because haskell prevented me from writing more programs that were incorrect. Errors and mistakes you would normally have to test for in other language can't even be compiled in Haskell. Nothing can totally eliminate testing but with haskell you can eliminate a huge portion of testing. So much so that programmers in haskell spend more time trying to get a program to compile than trying to test.
This power extends to refactoring. Most projects out there have problem domains that aren't fully defined and thus require refactoring changes in the future to better fit the problem domain. It's an inevitability. It often happens that such refactorings require massive and dangerous changes to code that has already accumulated immense complexity.
A common problem like this becomes trivial in haskell. Haskell forces your code to be modular so that such changes happen easily. The type system also ensures that if you do a change that is incorrect the compiler will catch it.
From a less tangible standpoint haskell also feels right. When you design things in other programming languages you're not sure where to cut your modules and how to correctly divide responsibility of your code and of course your mistakes become apparent over time. Haskell doesn't feel this way. It feels like the right approach to design and building primitives that snap together like legos. Over time this feeling will coalesce into understanding. You will completely understand why haskell programs are better designed then programs written in other languages.
I never mentioned performance. Although Haskell is very performant, haskell isn't suppose to answer the question of performance AND design (that's more rust) haskell just addresses design and safety. Additionally, it's not just haskell that has these qualities. It's actually the whole family of functional ML languages that haskell comes from that utilize Algebraic Data types and functional programming. You can achieve sort of the same philosophy I describe here by using something like Ocaml or Elm.
Also don't let the fact that haskell isn't mainstream put you off. Although it's not as practical, learning it is like taking the red pill. You'll never be the same.
- Jobmachine, an advanced job-scheduling system with dynamic dependency resolution[2]
- Vaultenv, a small open-source tool to get secrets from Hashicorp vault[3][4]
- alfred-margaret, a blazingly-fast Aho-Corasick implementation written in Haskell[5][6]
- Sharkmachine, our in-house replacement for Apache Spark[7]
[1]: https://tech.channable.com/
[2]: https://tech.channable.com/posts/2017-02-24-how-we-secretly-...
[3]: https://tech.channable.com/posts/2017-07-06-introducing-vaul...
[4]: https://github.com/channable/vaultenv
[5]: https://tech.channable.com/posts/2019-03-13-how-we-made-hask...
[6]: https://github.com/channable/alfred-margaret
[7]: https://tech.channable.com/posts/2019-10-04-why-we-decided-t...