Friend of mine is always trying to convert me. Asked me to read this yesterday evening. This is my take on the article:
Most of my daily job goes into gluing services (API endpoints to databases or other services, some business logic in the middle). I don't need to see yet another exposition of how to do algorithmic tasks. Haven't seen one of those since doing my BSc. Show me the tools available to write a daemon, an http server, API endpoints, ORM-type things and you will have provided me with tools to tackle what I do. I'll never write a binary tree or search or a linked list at work.
If you want to convince me, show me what I need to know to do what I do.
I've been using Haskell for quite a bit in production. My personal take, as an engineer who is generally skeptical of fancy language features:
Plus:
- The type system. It can make your life a huge pain, but in 99% of the cases, if the code compiles, it works. I find writing tests in Haskell somewhat pointless - the only places where it still has value is in gnarly business logic. But the vast majority of production code is just gluing stuff together
- Building DSLs is extremely quick and efficient. This makes it easy to define the business problem as a language and work with that. If you get it right, the code will be WAY more readable than most other languages, and safer as well
- It's pretty efficient
Minus
- The tooling is extremely bad. Compile times are horrendous. Don't even get me started on Stack/Cabal or whatever the new hotness might be
- Sometimes people get overly excited about avoiding do notation and the code looks very messy as a result
- There are so many ways of doing something that a lot of the time it becomes unclear how the code should look. But this true in a lot of languages
I never really understand why I would want a type system until I learned Rust and was forced to learn it. Now I don't understand what I was thinking before..
Yep, GHC is an incredible compiler and Haskell is an incredible language. If only Haskell had a package manager as slick as Cargo, I'd use it for just about everything.
The great news is that tooling is rapidly improving these days. VSCode with the new ghcide is simply amazing. Ghcide is still new and thus has a few rough edges (eg. TH) but overall it lifts the Haskell IDE experience into the 21st century. Give it a try.
What about runtime stuff? I've found Haskell is very good at abstracting away your concerns about the runtime considerations and sometimes it will come back to bite you. I mean all that stuff you want to see into when you're running your app in production, like caching, function invocation times, threads etc.
This is a good discussion of a problem that suits Haskell well, but it's unfair to Python in some respects.
For example: I haven't read or written a lot of Python in a while, but would Python programmers really want to implement mutation in such a class by copying dicts around? The hand-wringing about "oh no, I wrote the condition as not is_node" is silly since one could just define an is_leaf method that can be used without negation. And "changing heapToList to return a lazy sequence makes it no longer return a list, oh no!" is just as silly, since one would of course not do that but define a separate heapToSequence (and probably base heapToList on that).
Also: "pattern matching and algebraic data types which have massive, clear benefits and few (if any) downsides". They have downsides whenever your data is not tree-shaped. Yes, a lot of data is tree, but then a lot isn't. I work in compilers, which is often touted as a prime application of ML-family languages, and this is very true, but not 100%. If you can have sharing in your abstract syntax tree (like a goto node that might refer to a target node somewhere else in the tree), you start to have difficulties. And you get even more difficulties when you try to model control flow graphs and the like. Nothing insurmountable, but still things where it's suddenly good to have other tools than only algebraic datatypes. OCaml is good in this regard.
Haskell is a beautiful research language. Its usecase is to supply subjects for PhDs and MScs, which it fulfills perfectly. Also it's extremely fun to learn and play with.
I would never bring it to the production though, reasons being:
1) Production code should be understandable by an on-call person at 4 am. If business logic is buried under layers of lenses, monad transformers and arrows, good luck troubleshooting it under stress. And real systems do break, no matter type safety.
2) It's a research language, and a big part of the research is about control flow. And therefore haskell has _way too many_ ways to combine things: monad transformers of different flavors, applicative functors, arrows, iteratees, you name it. And libraries you find on hackage choose _different_ ways to combine things. In the business code you probably want to combine multiple libraries, and you inevitably end up with unholy mess of all these approaches. Dealing with it takes more time than writing business logic.
3) Developers look at these fancy research papers and try to reproduce them. As a result, very basic things become extremely hard and brittle. I saw a real-live example when applying a transform to all fields of a record took a team 2 days of discussion in slack, because "writing this manually?! it won't scale to record with 100 fields".
4) Architecture is extremely sensitive to the initial choices due to isolation of side effects. Because if you suddenly need to do something as simple as logging or reading a config in a place where it wasn't originally anticipated, you're in for a bumpy ride.
I've done commercial Haskell work and it was fantastic. Almost all of the things you mention are problems with technical leadership and not Haskell itself. These problems are all very, very easy to deal with.
1) Many of us have also seen the C++ library or application that busts out the template metaprograms at every opportunity. Haskell is the same. Use restraint when bringing in new libraries and programming techniques. (as an aside, I have yet to encounter a single problem that I thought merited the use of arrows)
2) You also see this in other languages, though to a lesser degree. The same techniques we use with other languages work just as well in Haskell: As leadership, form a strong opinion on the best way to write control flow and ensure that everything uses a consistent style.
3) Are your engineers running around implementing random research papers? This has nothing to do with Haskell.
4) In practice, this is almost never a big problem. Refactoring a pure function to an effectful function is easy and safe. In a production setting, almost all of your functions run in some monad already, so it's pretty rare to run into a situation where you suddenly need to percolate effects through many functions.
Many others have replied to your concerns already, nevertheless allow me to add my own experience to the pile, as someone writing Haskell for food:
1) For a team of Haskell programmers reading Haskell code is just the norm. It's the same as for a team of Python programmers reading Python code. Also as a side-note: I never in my 15 years of professional life had a 4am call. Maybe I'm lucky, I don't know. In my experience automated tests, code reviews, sane deployment policies, etc... all minimise the chance of this ever happening. Haskell's powerful type system helps a lot here as it saves you from a whole array of problems upfront. I feel much more confident deploying Haskell code to production than code in any other language.
2) In commercial projects engineers tend to do things in sane and simple ways. This is not surprising really. Just cause you can does not mean you should. It's not Haskell specific but a general principle ie. KISS.
3) "Fancy research papers" at times can actually be really helpful. If you happen to have a problem that someone wrote a paper about that saves you time having to rediscover the solution. Having lots of research papers is imho a great strength of Haskell. That being said KISS from above applies here. If your problem is simple then do it simply.
4) Architecture in general is much less sensitive to change in Haskell than in other languages in my experience as the type checker guides you when you want to change your code. Refactoring in Haskell is pure joy. Re logging/configuration/etc... there are well-known patterns to deal with these as you would imagine, it's not like no one had to solve these problems in Haskell before. There are also tools (eg. Debug.Trace) in case you need some quick ad-hoc printf-style debugging. The same really as in any other language.
I don't want to write about all the pros of the language, others have done so already, just wanted to add my own professional experience to the mix.
Agree with #1.
I think Elm is probably the best functional language in this regard. Contains all the important bits yet is small and opinionated enough to be easily readable.
If only weren't web only and run as a private project. An elm like language with llvm backend would be amazing
>Production code should be understandable by an on-call person at 4 am.
I don't like the "simple language means understandable code" argument being thrown around like it was some obvious fact. I'm currently working on a project whose major component is a byzantine home-grown message passing framework written in pretty much Java-in-C++ (old school OO with liberal use of shared pointers. Not that I would call C++ in any form "simple", but I do think that C++ without template magic is simpler than Haskell with GHC magic, or, say, any Lisp with a lot of macros). Maybe it's a case of grass being greener on the other side, but I'd gladly take a monad transformer stack or a DSL written in Lisp macros over doing the same song and a dance over and over again just to implent a tiny new functionality, or trying to deduce the logic from someone else's sea of boilerplate.
I mean, taking this logic to extreme, one could say that code written in assembly is easy to understand: it's adding a value to EAX now, then it jumps over there...
This being said, Haskell does have something in it that encourages one to design a ballistic algebra that runs in the type system before even pointing a gun at one's foot.
"1) Production code should be understandable by an on-call person at 4 am. If business logic is buried under layers of lenses, monad transformers and arrows, good luck troubleshooting it under stress. And real systems do break, no matter type safety."
Let's assume that your on call person is a developer. (If the person is not a developer, (s)he is not going to comprehend any language.)
1) If your application is written in Haskell, the on call developer would more than likely have been involved in the code base and reads Haskell. Your assertion about not comprehending it seems suspect.
2) You have a serious process issue if a developer is woken from a sound sleep to track down, correct, thoroughly test, and promote a fix for the bug in the middle of the night. The number of cases in which this happens should be close enough to zero to call it zero.
Your comment sounds like an attempt to cast Haskell as a purely academic language because it fails a (poorly) made up real world scenario. I'm NOT a Haskell-er so I don't feel a need to defend it. I do find the reasoning behind the criticism poorly thought out.
In my experience working in the largest Haskell team in the world, dealing with various applications and services in production: none of what you said is close to reality.
Then Haskell failed. To quote from Haskell 2010 Language Report, the primary goal of Haskell was: "It should be suitable for teaching, research, and applications, including building large systems".
Applications and building large systems are explicitly goals of Haskell. Haskell was never intended to be a research language.
> Production code should be understandable by an on-call person at 4 am. If business logic is buried under layers of lenses, monad transformers and arrows, good luck troubleshooting it under stress. And real systems do break, no matter type safety.
You can say the same thing about production Java code buried under layers of frameworks, factories, facades, proxies, aspects, annotations, etc. I don't see why readable, maintainable code can't be written as easily in Haskell as Java, C++, Python - you just have to make writing clean code a priority.
I think this points to a difference that I don't see highlighted enough - influential doesn't mean best.
If you are stuck on a plane are you going to watch citizen kane or something from the last couple of years. What about an Akira Kurosawa movie? They top film critics' lists of the 'best' movies, but really they are some of the most influential movies of all time.
Lisp and Haskell aren't the 'best' languages to use the vast majority of the time, but they heavily influential and have contributed a lot to computer science.
>4) Architecture is extremely sensitive to the initial choices due to isolation of side effects. Because if you suddenly need to do something as simple as logging or reading a config in a place where it wasn't originally anticipated, you're in for a bumpy ride.
Not a serious Haskeller at all, so not sure if this is a terrible practice, but for logging, `unsafePerformIO` could work in a pinch without changing types.
Cute how none of this relates to the article. Why do you have a list of straw-man bullet points to rattle off whenever someone says "Haskell"? Who hurt you?
I've worked at multiple Haskell shops. They've all had problems. None of the problems were actually attributable to Haskell..but Haskell was an easy target for blame by management. I'd say that's Haskell's biggest problem in a professional setting.
I know Haskell and Go about equally. Meaning I know all the language features & common libs & have a grip on their runtimes. Go on day 1 was way easier to write and understand than Haskell on day 1. Now that I've normalized their learning curves, Go didn't get much easier to work with. Haskell did - I use my brain way less when writing Haskell than when writing Go.
But even then, Haskell or Go. It's all just the same stuff.
I've pretty much given up talking on the Internet to people about Haskell. Arguing against some of the pts in this thread about how Haskell isn't good for production.
I'll continue to write Haskell for pay for the foreseeable future. If I'm lucky, I'll do it the rest of my career. I don't see any reason why not.
> ..but Haskell was an easy target for blame by management. I'd say that's Haskell's biggest problem in a professional setting.
I would say that's a software company's biggest problem instead. I really don't understand how someone with little or no coding experience can be in a leadership position with other programmers who are supposed to be problem solvers and have all the details of how to build something.
The bigger the gap in knowledge, the more communication breaks down and the hierarchical structure becomes useless.
This comment pretty much sums up my own experience, including learning Go, then Haskell, and the final takeaway - have pretty much given up talking on the internet about Haskell.
Python may be terrible, but this poster doesn't know Python at all. Here's how to fix the first snippet:
leaf = object()
Huh, that's funny, it's shorter than the Haskell? Why is that? Let's keep going.
def merge(lhs, rhs):
if lhs is leaf: return rhs
if rhs is leaf: return lhs
if lhs[0] <= rhs[0]: return lhs[0], merge(rhs, lhs[2]), lhs[1]
return rhs[0], merge(lhs, rhs[2]), rhs[1]
Ugh. My mouth tastes funny. Livecoding on this site is always disorienting. I need to sit down for a bit. Exercise for the reader: Continue on in this style and figure out whether the Haskell really deserves its reputation for terseness and directness.
Edit: I kept reading and was immediately sick. __dict__ abuse is a real problem in our society, folks. It's not okay.
The Haskell memes are growing stronger as I delve deeper into this jungle. The pop-minimum function here is a true abomination, breaking all SOLID principles at once. I can only imagine what it might look like in a less eldritch setting:
def popMin(tree):
if tree is leaf: raise IndexError("popMin from leaf")
return tree[0], merge(tree[1], tree[2])
We continue to clean up the monstrous camp.
def listToHeap(elts):
rv = leaf
for elt in elts:
rv = insert(rv, elt)
return rv
The monster...they knew! They could have done something better and chose not to. They left notes suggesting an alternative implementation:
def heapToList(tree):
rv = []
while tree is not leaf:
datum, tree = popMin(tree)
rv.append(datum)
return rv
And again, the monster left plans, using one of the forbidden tools. We will shun the forbidden tools even here and now. We will instead remind folks that Hypothesis [0] is a thing.
Haskell's an alright language. Python's an alright language. They're about the same age. If one is going to write good Haskell, one might as well write good Python, too.
I got curious about Haskell some years ago because of a complete career disappointed with other languages. Ive put out some semi big apps in this language, that have been working well in production. I code for fun and Haskell is the most fun. Sure, there has been a couple of problems with tooling and its hard to find best practices, but I seem to be able to live with. I get a little depressed when having to work with other languages. For me its the end game.
I think python was a poor comparison here. The claim "python doesn't have algebraic data types" doesn't really make sense. Algebraic data types let something be an X or a Y. In python, everything can be an X, or a Y, or a Z, or anything else. In the tree example, an ideomatic tree structure in python would just be a 3-tuple (left, right, value). There's no need to define anything.
Don't get me wrong, I'm all for algebraic data types and think every statically typed language should have them, but it's nonsensical to talk about them in the context of a dynamically typed language.
The author commented elsewhere on this page that the article was mostly a response to missing these features in golang - I think that would've been a much clearer comparison that showed what you were really missing.
One thing that makes programming difficult is how much context needs to be held in the live part of the brain. Past N items (let's say 4), the brain has to swap those values and it makes programming much much slower.
Most of the article is spent explaining this sideways; with Haskell you need to hold less aspects in the head because they are either eliminated entirely (purity) or can be deferred to the compiler (types), ... What we learn is that Haskell is easier to implement tree-like structures.
I think this is what most language proselytes are trying to convey in their articles. But don't talk about explicitly. Inevitably they will pick a task that is easy to achieve in the language because the developer environment aligns well for that use-case, and then let the reader infer that this applies to all programming tasks.
Basically we are trying to benchmark humans, without building a proper model of how humans work. The next evolution in programming will be done by properly understanding how we work and interact with the computer.
My Haskell isn't good enough to translate, but I'd love to see these examples in Rust. I believe Rust has all of the Haskell features mentioned in this article, but with a much more familiar syntax.
This is actually one of my main two beefs with Haskell:
. The language is really interesting from a feature point of view, but the syntax, oh man. Looking at Haskell code when you switch back and forth from a more conventional language (C/C++/JS/Java/C#/Python/etc...) is a major headache. I can switch from C++ to Python without a second thought. Not so with Haskell.
. You can't really predict how something will actually execute, that's left to the language to decide. While in some situations this is a desirable feature, in many, it isn't at all, especially if you're writing performance critical code.
I can’t say for Haskell, but I can say for Lisp, which similarly gets these “look how great” articles but also similarly doesn’t see a huge up-tick in usage.
Whether you’re a student fresh out of school, or you’ve been unemployed for 10 years as a sysadmin, or you’re an expert programmer already, Common Lisp is accessible to you. Those examples are real; they’re backgrounds of folks I either used to or currently work with. Being paid helps immensely.
So it’s not that the language is unlearnable, unreadable, or out-of-reach. (The pot-shots that random commenters in forums like these take on the language are usually shallow or even outright wrong.) In some cases, it’s even demonstrated to be asymptotically more productive.
So what’s the deal? I personally think it’s just that productivity isn’t in and of itself incentivizing enough. You know Python and C++, you’re relatively proficient at them, you know how to get the job done with them, why learn something new? Haskell/Lisp won’t get you a job (necessarily), it won’t allow you to do something with a computer that you fundamentally couldn’t do before, and it’ll suck up a lot of your time to figure out what’s going on with them. Moreover, there’s no big organization behind it (like Mozilla or Facebook or Microsoft or ...) so where’s the credibility? A bunch of researchers at some university? A bunch of open-source hackers?
I think one has to be personally invested in becoming a broadly more knowledgeable and more skilled programmer, just for the sake of it, and (IME) most people aren’t like that. I think one has to also have a penchant for finding simpler or more fundamental ways of solving problems, and that has to turn into an exploratory drive. Even if one is like that, learning Haskell is one of a hundred possible paths to improve oneself.
My comment shouldn’t be misconstrued as supporting a mindset of it being OK to just know a couple languages well. I think the hallmark of an excellent programmer is precisely this broad knowledge of not just tools, but ways of thinking, in order to solve the gnarly problems that come up in software.
First, it doesn't fit everywhere. The best advice I received is that FP fits best when you can think about your program as a pipe - data comes in, data goes out. The more your program doesn't look like that, the less well FP fits.
Now, Haskell can do non-FP things, but you're fighting against the nature of the language to do so. It's probably better to pick a language that you don't have to fight in order to write your program.
Second (though I'm not sure that this is actually a reason that people pay attention to): Compile time. How long does Haskell take to compile a multi-million-line code base? How long does Go take? (Yes, I know that Haskell may take fewer lines. It won't be enough fewer to make the compile time shorter, though, nor anywhere close.) If you've got a multi-million-line code base, you've probably got a reasonably large team, and you've probably had them for years. If they each compile, say, five times per day, and there are twenty of them, and they've been doing it for ten years, the time spent in compiling adds up to real serious money lost.
Third: For a large team, they won't all be A students. Half the programmers will be below average. I'm not sure that Haskell is a great language for them. I wonder if they can't do more damage with Haskell than they could with, say, Go. (Of course, they could do a lot of damage with C++, too...)
Well, adoption rates of programming languages has almost nothing to do with the features and qualities of the language itself. Swift is big because it's backed by Apple, Go is big because it's backed by Google, Javascript because it's on the web, etc. Python might actually be the only language that succeeded "on its merits" to some extent, and even then it seems more to do with some early success and libraries than the core nature of the language itself.
As the author of the post, I don't actually think I can make a compelling argument for why someone should switch to using Haskell in their day job. I don't have real experience in the software engineering industry, and from what little I do know language choice doesn't make a huge difference.
That said, I think it's valid to say that a given pattern is bad, or another pattern is better. I was trying to argue for that in the post in a couple cases that I think Haskell does well.
> So, for a programming language that has so much to offer, why isn't it adopted more?
In my experience it's usually some combination of FUD echoed throughout these comments such as:
Haskell is an academic language and cannot be understood be mere mortals
Well everyone is mortal and some people have learned Haskell so this is obviously hyperbole and meaningless. Is it difficult to understand? Yes... but I have a theory that this is largely because we aren't taught to think in the way Haskell asks us to. Most of us in industry invariably learn Haskell as a second or third language and by then certain patterns and expectations are present in our brains that we hold as truths.
The tragedy of this argument is that people think you have to understand everything in Haskell in order to get started. They point to more advanced features like lenses and profunctor optics and all of this jargon as proof. However I don't ever recall having to learn the entirety of template metaprogramming to get started in C++.
There's really a pyramid of features and the amount of Haskell you need to know to get started is small.
It is too hard to hire Haskell programmers
It's as hard as you make it out to be. There are plenty of people out there who would love to program in Haskell for their day job. When I started posting jobs for Haskell programmers my queue was full, constantly.
The problem is that unless your organization is fully invested in Haskell people in your organization will find ways to hijack this process in order to make it come true by moving the goal posts. It might be hard to find Haskell programmers in your area so they'll say you can't hire remote developers. Say you'll train people up into Haskell and they'll say we don't have anyone experienced enough, or not enough time, etc, etc.
It's not hard to hire programmers. It's hard dealing with people who don't want Haskell to be adopted in your org.
The documentation is poor, there aren't enough libraries, etc
This may have been true more than ten years ago but it no longer holds. The documentation is phenomenal. It seems rough if you're not used to reading type signatures. However once you are familiar with rudimentary levels of Haskell this disappears fast. Haskell is documented. Whenever you add a top-level signature you're adding documentation that not only enriches the program but documentation that cannot be wrong, go out of date, etc.
I think this one gets bandied around a lot by developers from big ecosystems that have deep corporate pockets to fund the development of frameworks, libraries, and tooling. Haskell has been getting more of that but it's still nothing compared to Java/.NET/Swift, etc.
Regardless there are libraries for every common task and ones that can do things with Haskell's type system that you simply cannot in other languages (or can only emulate, poorly, with possibly buggy run-time code introspections, templates, macros, etc).
The real world is messy and Haskell's type system just gets in the way
The real world is messy so why would you want to use a tool that makes incorrect programs permissible?
This comes up from folks who like how easy it is to get started with dynamic languages which are permissive about their inputs. I like this property of dynamic languages too.
What I don't like is all of the run time inspection I have to do in order to know what data is safe to use. At first this doesn't seem like a problem with unit tests and a tight feedback loop. However at larger scales in a code base it makes refactoring and reasoning about high-level patterns much harder. And despite the claim that "type errors are rarely ever the source of production issues anyway," I still find TypeError: undefined is not a function in logs more often than they'd like to think.
The point of all this is that we ship this code confident that we probably nailed ~85% of the problem and we tolerate the risk that there will be some number of errors that will be reported after the fact. Ship early and ship often. However in practice this sucks up a lot of time as a project matures.
I rather like the experience of not having to chase down where an errant null check as missed or where some code mistakenly mutated a shallow copy. I don't even have to think about that in Haskell. I can focus on the business domain logic.
It’s hilarious to read all kinds of rationalizations for why haskell is not useful.
Servant + Aeson beats any api backend in any language, period. If you combine that with Elm on the frontend you’ve got a great onboarding path for new devs to learn enough haskell to work on the backend.
Of course, for production, ignore lenses, monad transformers, free monads, effect systems, etc. They’re awesome, but the complexity is not worth it in practice at this time.
This article reminds of my coworker, touts Haskell all the time, ends up writing shitty Java code which is difficult to understand and performs like molasses.
Real world is not perfect, it is immutable with plenty of side effects. Using Haskell for day to day messy work is not trivial and should not be considered IMO, u nless you have Haskell gurus all around.
I would rather take a dumb language like Go or Java over Haskell for work code.
tldr: I am NEVER nervous about refactoring some Haskell code.
Good:
After working in a variety of organizations using, typed but also dynamic languages I'm now writing all my back-end code in Haskell. I'm becoming more and more convinced that for multi-year, multi-programmer applications (a language like) Haskell is the only way to make it sustainable, while still being able to add features.
It's difficult to say to someone "Just go read books for a couple of months because you need to understand purity, laziness, cross compilation, monad transformers (go read The Book of Monads), 20+ language pragmas. etc etc"
It does however feel like I'm learning useful stuff, and it's a lot of fun to get an executable that runs FAST.
"While it solves the problem of methods, and the mutation problem, it has a serious bug. We can’t have None as an element in the tree!"
Uhm... what?! Why not? You check that your left and right are None and if they are it is a leaf. And if they are not it is not. What your data value is doesn't matter and you can have as many None values in the tree as you like. Your tree doesn't need leaves to define where it ends, it ends when there are no more branches.
I think Haskell is conceptually cool, but I just can't stand its symbols and grammars. To me, "=>" means comparison and "|" means an OR, and I'm cringed to see $s and \s in a program code that makes it look like LaTeX. I also prefer the boundary of terms and expressions to be consistently marked up with parenthesis. I know this is just a matter of taste, but sometimes it affects your motivation a lot.
For those who were wondering about seeing this in Swift. You probably weren't, and I'm aware I could've leaned a bit harder on things that were built-in, but I was basically trying to meet in the middle between representing the Haskell code as written in the interview and something vaguely Swifty.
[+] [-] Beltiras|6 years ago|reply
Most of my daily job goes into gluing services (API endpoints to databases or other services, some business logic in the middle). I don't need to see yet another exposition of how to do algorithmic tasks. Haven't seen one of those since doing my BSc. Show me the tools available to write a daemon, an http server, API endpoints, ORM-type things and you will have provided me with tools to tackle what I do. I'll never write a binary tree or search or a linked list at work.
If you want to convince me, show me what I need to know to do what I do.
[+] [-] gabipurcaru|6 years ago|reply
Plus:
- The type system. It can make your life a huge pain, but in 99% of the cases, if the code compiles, it works. I find writing tests in Haskell somewhat pointless - the only places where it still has value is in gnarly business logic. But the vast majority of production code is just gluing stuff together
- Building DSLs is extremely quick and efficient. This makes it easy to define the business problem as a language and work with that. If you get it right, the code will be WAY more readable than most other languages, and safer as well
- It's pretty efficient
Minus
- The tooling is extremely bad. Compile times are horrendous. Don't even get me started on Stack/Cabal or whatever the new hotness might be
- Sometimes people get overly excited about avoiding do notation and the code looks very messy as a result
- There are so many ways of doing something that a lot of the time it becomes unclear how the code should look. But this true in a lot of languages
[+] [-] atoav|6 years ago|reply
[+] [-] roar-of-time|6 years ago|reply
[+] [-] pwm|6 years ago|reply
[+] [-] verttii|6 years ago|reply
[+] [-] the_af|6 years ago|reply
Is Stack not adequate? I thought the consensus was that it was ok. Is it really more horrible than say Maven or SBT or whatever in other languages?
[+] [-] tom_mellior|6 years ago|reply
For example: I haven't read or written a lot of Python in a while, but would Python programmers really want to implement mutation in such a class by copying dicts around? The hand-wringing about "oh no, I wrote the condition as not is_node" is silly since one could just define an is_leaf method that can be used without negation. And "changing heapToList to return a lazy sequence makes it no longer return a list, oh no!" is just as silly, since one would of course not do that but define a separate heapToSequence (and probably base heapToList on that).
Also: "pattern matching and algebraic data types which have massive, clear benefits and few (if any) downsides". They have downsides whenever your data is not tree-shaped. Yes, a lot of data is tree, but then a lot isn't. I work in compilers, which is often touted as a prime application of ML-family languages, and this is very true, but not 100%. If you can have sharing in your abstract syntax tree (like a goto node that might refer to a target node somewhere else in the tree), you start to have difficulties. And you get even more difficulties when you try to model control flow graphs and the like. Nothing insurmountable, but still things where it's suddenly good to have other tools than only algebraic datatypes. OCaml is good in this regard.
[+] [-] platz|6 years ago|reply
[+] [-] h91wka|6 years ago|reply
I would never bring it to the production though, reasons being:
1) Production code should be understandable by an on-call person at 4 am. If business logic is buried under layers of lenses, monad transformers and arrows, good luck troubleshooting it under stress. And real systems do break, no matter type safety.
2) It's a research language, and a big part of the research is about control flow. And therefore haskell has _way too many_ ways to combine things: monad transformers of different flavors, applicative functors, arrows, iteratees, you name it. And libraries you find on hackage choose _different_ ways to combine things. In the business code you probably want to combine multiple libraries, and you inevitably end up with unholy mess of all these approaches. Dealing with it takes more time than writing business logic.
3) Developers look at these fancy research papers and try to reproduce them. As a result, very basic things become extremely hard and brittle. I saw a real-live example when applying a transform to all fields of a record took a team 2 days of discussion in slack, because "writing this manually?! it won't scale to record with 100 fields".
4) Architecture is extremely sensitive to the initial choices due to isolation of side effects. Because if you suddenly need to do something as simple as logging or reading a config in a place where it wasn't originally anticipated, you're in for a bumpy ride.
[+] [-] implicit|6 years ago|reply
1) Many of us have also seen the C++ library or application that busts out the template metaprograms at every opportunity. Haskell is the same. Use restraint when bringing in new libraries and programming techniques. (as an aside, I have yet to encounter a single problem that I thought merited the use of arrows)
2) You also see this in other languages, though to a lesser degree. The same techniques we use with other languages work just as well in Haskell: As leadership, form a strong opinion on the best way to write control flow and ensure that everything uses a consistent style.
3) Are your engineers running around implementing random research papers? This has nothing to do with Haskell.
4) In practice, this is almost never a big problem. Refactoring a pure function to an effectful function is easy and safe. In a production setting, almost all of your functions run in some monad already, so it's pretty rare to run into a situation where you suddenly need to percolate effects through many functions.
[+] [-] pwm|6 years ago|reply
1) For a team of Haskell programmers reading Haskell code is just the norm. It's the same as for a team of Python programmers reading Python code. Also as a side-note: I never in my 15 years of professional life had a 4am call. Maybe I'm lucky, I don't know. In my experience automated tests, code reviews, sane deployment policies, etc... all minimise the chance of this ever happening. Haskell's powerful type system helps a lot here as it saves you from a whole array of problems upfront. I feel much more confident deploying Haskell code to production than code in any other language.
2) In commercial projects engineers tend to do things in sane and simple ways. This is not surprising really. Just cause you can does not mean you should. It's not Haskell specific but a general principle ie. KISS.
3) "Fancy research papers" at times can actually be really helpful. If you happen to have a problem that someone wrote a paper about that saves you time having to rediscover the solution. Having lots of research papers is imho a great strength of Haskell. That being said KISS from above applies here. If your problem is simple then do it simply.
4) Architecture in general is much less sensitive to change in Haskell than in other languages in my experience as the type checker guides you when you want to change your code. Refactoring in Haskell is pure joy. Re logging/configuration/etc... there are well-known patterns to deal with these as you would imagine, it's not like no one had to solve these problems in Haskell before. There are also tools (eg. Debug.Trace) in case you need some quick ad-hoc printf-style debugging. The same really as in any other language.
I don't want to write about all the pros of the language, others have done so already, just wanted to add my own professional experience to the mix.
[+] [-] rishav_sharan|6 years ago|reply
If only weren't web only and run as a private project. An elm like language with llvm backend would be amazing
[+] [-] thedataangel|6 years ago|reply
[+] [-] antisemiotic|6 years ago|reply
I don't like the "simple language means understandable code" argument being thrown around like it was some obvious fact. I'm currently working on a project whose major component is a byzantine home-grown message passing framework written in pretty much Java-in-C++ (old school OO with liberal use of shared pointers. Not that I would call C++ in any form "simple", but I do think that C++ without template magic is simpler than Haskell with GHC magic, or, say, any Lisp with a lot of macros). Maybe it's a case of grass being greener on the other side, but I'd gladly take a monad transformer stack or a DSL written in Lisp macros over doing the same song and a dance over and over again just to implent a tiny new functionality, or trying to deduce the logic from someone else's sea of boilerplate.
I mean, taking this logic to extreme, one could say that code written in assembly is easy to understand: it's adding a value to EAX now, then it jumps over there...
This being said, Haskell does have something in it that encourages one to design a ballistic algebra that runs in the type system before even pointing a gun at one's foot.
[+] [-] bpyne|6 years ago|reply
Let's assume that your on call person is a developer. (If the person is not a developer, (s)he is not going to comprehend any language.)
1) If your application is written in Haskell, the on call developer would more than likely have been involved in the code base and reads Haskell. Your assertion about not comprehending it seems suspect.
2) You have a serious process issue if a developer is woken from a sound sleep to track down, correct, thoroughly test, and promote a fix for the bug in the middle of the night. The number of cases in which this happens should be close enough to zero to call it zero.
Your comment sounds like an attempt to cast Haskell as a purely academic language because it fails a (poorly) made up real world scenario. I'm NOT a Haskell-er so I don't feel a need to defend it. I do find the reasoning behind the criticism poorly thought out.
[+] [-] vapou|6 years ago|reply
In my experience working in the largest Haskell team in the world, dealing with various applications and services in production: none of what you said is close to reality.
[+] [-] sanxiyn|6 years ago|reply
Applications and building large systems are explicitly goals of Haskell. Haskell was never intended to be a research language.
[+] [-] excursionist|6 years ago|reply
You can say the same thing about production Java code buried under layers of frameworks, factories, facades, proxies, aspects, annotations, etc. I don't see why readable, maintainable code can't be written as easily in Haskell as Java, C++, Python - you just have to make writing clean code a priority.
[+] [-] BubRoss|6 years ago|reply
If you are stuck on a plane are you going to watch citizen kane or something from the last couple of years. What about an Akira Kurosawa movie? They top film critics' lists of the 'best' movies, but really they are some of the most influential movies of all time.
Lisp and Haskell aren't the 'best' languages to use the vast majority of the time, but they heavily influential and have contributed a lot to computer science.
[+] [-] leoh|6 years ago|reply
Not a serious Haskeller at all, so not sure if this is a terrible practice, but for logging, `unsafePerformIO` could work in a pinch without changing types.
[+] [-] ukj|6 years ago|reply
This is fundamentally why it's useless in practice. It requires you to anticipate/predict everything ahead of implementation.
It requires you to be perfect at Waterfall ( https://en.wikipedia.org/wiki/Waterfall_model ).
Real-world problems laugh at such idealism.
[+] [-] 08-15|6 years ago|reply
[+] [-] lallysingh|6 years ago|reply
That's a huge red flag.
As for the rest.. I don't think the language was the problem at that team.
[+] [-] whateveracct|6 years ago|reply
I know Haskell and Go about equally. Meaning I know all the language features & common libs & have a grip on their runtimes. Go on day 1 was way easier to write and understand than Haskell on day 1. Now that I've normalized their learning curves, Go didn't get much easier to work with. Haskell did - I use my brain way less when writing Haskell than when writing Go.
But even then, Haskell or Go. It's all just the same stuff.
I've pretty much given up talking on the Internet to people about Haskell. Arguing against some of the pts in this thread about how Haskell isn't good for production.
I'll continue to write Haskell for pay for the foreseeable future. If I'm lucky, I'll do it the rest of my career. I don't see any reason why not.
[+] [-] proc0|6 years ago|reply
I would say that's a software company's biggest problem instead. I really don't understand how someone with little or no coding experience can be in a leadership position with other programmers who are supposed to be problem solvers and have all the details of how to build something. The bigger the gap in knowledge, the more communication breaks down and the hierarchical structure becomes useless.
[+] [-] bojo|6 years ago|reply
[+] [-] lidHanteyk|6 years ago|reply
Edit: I kept reading and was immediately sick. __dict__ abuse is a real problem in our society, folks. It's not okay.
The Haskell memes are growing stronger as I delve deeper into this jungle. The pop-minimum function here is a true abomination, breaking all SOLID principles at once. I can only imagine what it might look like in a less eldritch setting: We continue to clean up the monstrous camp. The monster...they knew! They could have done something better and chose not to. They left notes suggesting an alternative implementation: Similarly, if we look before we leap: And again, the monster left plans, using one of the forbidden tools. We will shun the forbidden tools even here and now. We will instead remind folks that Hypothesis [0] is a thing.Haskell's an alright language. Python's an alright language. They're about the same age. If one is going to write good Haskell, one might as well write good Python, too.
[0] https://hypothesis.works/
[+] [-] fistOfKross|6 years ago|reply
[+] [-] ekimekim|6 years ago|reply
Don't get me wrong, I'm all for algebraic data types and think every statically typed language should have them, but it's nonsensical to talk about them in the context of a dynamically typed language.
The author commented elsewhere on this page that the article was mostly a response to missing these features in golang - I think that would've been a much clearer comparison that showed what you were really missing.
[+] [-] zimbatm|6 years ago|reply
Most of the article is spent explaining this sideways; with Haskell you need to hold less aspects in the head because they are either eliminated entirely (purity) or can be deferred to the compiler (types), ... What we learn is that Haskell is easier to implement tree-like structures.
I think this is what most language proselytes are trying to convey in their articles. But don't talk about explicitly. Inevitably they will pick a task that is easy to achieve in the language because the developer environment aligns well for that use-case, and then let the reader infer that this applies to all programming tasks.
Basically we are trying to benchmark humans, without building a proper model of how humans work. The next evolution in programming will be done by properly understanding how we work and interact with the computer.
[+] [-] nicoburns|6 years ago|reply
The tree data type in Rust could be:
[+] [-] sampo|6 years ago|reply
[+] [-] ur-whale|6 years ago|reply
This is actually one of my main two beefs with Haskell:
[+] [-] contravariant|6 years ago|reply
With data in the leaves you could easily do something like:
using the new dataclasses module. You could also add a type parameter to the above if you really wanted to.The pattern matching will need to be done manually though, following python's philosophy of duck-typing.
Edit: An alternative involves abusing the pattern matching that python does have to write things like:
but whether that's really a good idea is debatable.[+] [-] axilmar|6 years ago|reply
So, for a programming language that has so much to offer, why isn't it adopted more?
Could it be that it doesn't actually increase productivity to such a degree to justify the cost of change?
Legit question, I am not trying to be a troll.
[+] [-] reikonomusha|6 years ago|reply
Whether you’re a student fresh out of school, or you’ve been unemployed for 10 years as a sysadmin, or you’re an expert programmer already, Common Lisp is accessible to you. Those examples are real; they’re backgrounds of folks I either used to or currently work with. Being paid helps immensely.
So it’s not that the language is unlearnable, unreadable, or out-of-reach. (The pot-shots that random commenters in forums like these take on the language are usually shallow or even outright wrong.) In some cases, it’s even demonstrated to be asymptotically more productive.
So what’s the deal? I personally think it’s just that productivity isn’t in and of itself incentivizing enough. You know Python and C++, you’re relatively proficient at them, you know how to get the job done with them, why learn something new? Haskell/Lisp won’t get you a job (necessarily), it won’t allow you to do something with a computer that you fundamentally couldn’t do before, and it’ll suck up a lot of your time to figure out what’s going on with them. Moreover, there’s no big organization behind it (like Mozilla or Facebook or Microsoft or ...) so where’s the credibility? A bunch of researchers at some university? A bunch of open-source hackers?
I think one has to be personally invested in becoming a broadly more knowledgeable and more skilled programmer, just for the sake of it, and (IME) most people aren’t like that. I think one has to also have a penchant for finding simpler or more fundamental ways of solving problems, and that has to turn into an exploratory drive. Even if one is like that, learning Haskell is one of a hundred possible paths to improve oneself.
My comment shouldn’t be misconstrued as supporting a mindset of it being OK to just know a couple languages well. I think the hallmark of an excellent programmer is precisely this broad knowledge of not just tools, but ways of thinking, in order to solve the gnarly problems that come up in software.
[+] [-] AnimalMuppet|6 years ago|reply
First, it doesn't fit everywhere. The best advice I received is that FP fits best when you can think about your program as a pipe - data comes in, data goes out. The more your program doesn't look like that, the less well FP fits.
Now, Haskell can do non-FP things, but you're fighting against the nature of the language to do so. It's probably better to pick a language that you don't have to fight in order to write your program.
Second (though I'm not sure that this is actually a reason that people pay attention to): Compile time. How long does Haskell take to compile a multi-million-line code base? How long does Go take? (Yes, I know that Haskell may take fewer lines. It won't be enough fewer to make the compile time shorter, though, nor anywhere close.) If you've got a multi-million-line code base, you've probably got a reasonably large team, and you've probably had them for years. If they each compile, say, five times per day, and there are twenty of them, and they've been doing it for ten years, the time spent in compiling adds up to real serious money lost.
Third: For a large team, they won't all be A students. Half the programmers will be below average. I'm not sure that Haskell is a great language for them. I wonder if they can't do more damage with Haskell than they could with, say, Go. (Of course, they could do a lot of damage with C++, too...)
[+] [-] unknown|6 years ago|reply
[deleted]
[+] [-] oisdk|6 years ago|reply
As the author of the post, I don't actually think I can make a compelling argument for why someone should switch to using Haskell in their day job. I don't have real experience in the software engineering industry, and from what little I do know language choice doesn't make a huge difference.
That said, I think it's valid to say that a given pattern is bad, or another pattern is better. I was trying to argue for that in the post in a couple cases that I think Haskell does well.
[+] [-] agentultra|6 years ago|reply
In my experience it's usually some combination of FUD echoed throughout these comments such as:
Haskell is an academic language and cannot be understood be mere mortals
Well everyone is mortal and some people have learned Haskell so this is obviously hyperbole and meaningless. Is it difficult to understand? Yes... but I have a theory that this is largely because we aren't taught to think in the way Haskell asks us to. Most of us in industry invariably learn Haskell as a second or third language and by then certain patterns and expectations are present in our brains that we hold as truths.
The tragedy of this argument is that people think you have to understand everything in Haskell in order to get started. They point to more advanced features like lenses and profunctor optics and all of this jargon as proof. However I don't ever recall having to learn the entirety of template metaprogramming to get started in C++.
There's really a pyramid of features and the amount of Haskell you need to know to get started is small.
It is too hard to hire Haskell programmers
It's as hard as you make it out to be. There are plenty of people out there who would love to program in Haskell for their day job. When I started posting jobs for Haskell programmers my queue was full, constantly.
The problem is that unless your organization is fully invested in Haskell people in your organization will find ways to hijack this process in order to make it come true by moving the goal posts. It might be hard to find Haskell programmers in your area so they'll say you can't hire remote developers. Say you'll train people up into Haskell and they'll say we don't have anyone experienced enough, or not enough time, etc, etc.
It's not hard to hire programmers. It's hard dealing with people who don't want Haskell to be adopted in your org.
The documentation is poor, there aren't enough libraries, etc
This may have been true more than ten years ago but it no longer holds. The documentation is phenomenal. It seems rough if you're not used to reading type signatures. However once you are familiar with rudimentary levels of Haskell this disappears fast. Haskell is documented. Whenever you add a top-level signature you're adding documentation that not only enriches the program but documentation that cannot be wrong, go out of date, etc.
I think this one gets bandied around a lot by developers from big ecosystems that have deep corporate pockets to fund the development of frameworks, libraries, and tooling. Haskell has been getting more of that but it's still nothing compared to Java/.NET/Swift, etc.
Regardless there are libraries for every common task and ones that can do things with Haskell's type system that you simply cannot in other languages (or can only emulate, poorly, with possibly buggy run-time code introspections, templates, macros, etc).
The real world is messy and Haskell's type system just gets in the way
The real world is messy so why would you want to use a tool that makes incorrect programs permissible?
This comes up from folks who like how easy it is to get started with dynamic languages which are permissive about their inputs. I like this property of dynamic languages too.
What I don't like is all of the run time inspection I have to do in order to know what data is safe to use. At first this doesn't seem like a problem with unit tests and a tight feedback loop. However at larger scales in a code base it makes refactoring and reasoning about high-level patterns much harder. And despite the claim that "type errors are rarely ever the source of production issues anyway," I still find TypeError: undefined is not a function in logs more often than they'd like to think.
The point of all this is that we ship this code confident that we probably nailed ~85% of the problem and we tolerate the risk that there will be some number of errors that will be reported after the fact. Ship early and ship often. However in practice this sucks up a lot of time as a project matures.
I rather like the experience of not having to chase down where an errant null check as missed or where some code mistakenly mutated a shallow copy. I don't even have to think about that in Haskell. I can focus on the business domain logic.
[+] [-] cannabis_sam|6 years ago|reply
Servant + Aeson beats any api backend in any language, period. If you combine that with Elm on the frontend you’ve got a great onboarding path for new devs to learn enough haskell to work on the backend.
Of course, for production, ignore lenses, monad transformers, free monads, effect systems, etc. They’re awesome, but the complexity is not worth it in practice at this time.
[+] [-] acroback|6 years ago|reply
Real world is not perfect, it is immutable with plenty of side effects. Using Haskell for day to day messy work is not trivial and should not be considered IMO, u nless you have Haskell gurus all around.
I would rather take a dumb language like Go or Java over Haskell for work code.
[+] [-] mbo|6 years ago|reply
Perhaps we should use a language that is immutable and can reason about side-effects. Like Haskell?
[+] [-] TheSmoke|6 years ago|reply
[+] [-] chungus|6 years ago|reply
Good:
After working in a variety of organizations using, typed but also dynamic languages I'm now writing all my back-end code in Haskell. I'm becoming more and more convinced that for multi-year, multi-programmer applications (a language like) Haskell is the only way to make it sustainable, while still being able to add features.
Stephen Diehl has a great writeup on "what he wish he knew when he was learning haskell" http://dev.stephendiehl.com/hask/
It's difficult to say to someone "Just go read books for a couple of months because you need to understand purity, laziness, cross compilation, monad transformers (go read The Book of Monads), 20+ language pragmas. etc etc"
It does however feel like I'm learning useful stuff, and it's a lot of fun to get an executable that runs FAST.
[+] [-] MadWombat|6 years ago|reply
"While it solves the problem of methods, and the mutation problem, it has a serious bug. We can’t have None as an element in the tree!"
Uhm... what?! Why not? You check that your left and right are None and if they are it is a leaf. And if they are not it is not. What your data value is doesn't matter and you can have as many None values in the tree as you like. Your tree doesn't need leaves to define where it ends, it ends when there are no more branches.
[+] [-] euske|6 years ago|reply
[+] [-] zapzupnz|6 years ago|reply
https://gitlab.com/snippets/1900852
[+] [-] tu7001|6 years ago|reply