There’s one case where I think TH is a win: to auto-derive lenses (e.g. mkLenses). Of course, you’re not writing your own Template Haskell when you do this. That said, if you’re used to Clojure macros, and new to Haskell, you should follow this rule. It’s extremely rare that you need to use TH, especially with GHC.Generics. Virtually every case where you’d want to use TH has already been covered by a library. Also, Haskell does a lot of extremely sophisticated stuff (e.g. fusion) that makes the performance argument behind macros in Lisps meaningless. (Yes, I’ve seen Common Lisp programs that used macros for performance. With GHC, that kind of thing should never be needed.)
Documentation is abysmal.
True, but I think that it’s actually very good relative to the size of the Haskell community and what this entails sociologically. When I tried to build up a Haskell presence at my last job, I had to spend so much time justifying the use of Haskell (that is, playing goddamn politics) that I got a sense of what it means to be fighting for your life. Haskell has a small community of besieged, elite engineers who have to fight off “Why aren’t you just using Java?” mediocrity from all angles. It’s not surprising that the quality of documentation wouldn’t be at, say, the Python or Clojure level.
We’d have great documentation in Haskell if (a) more people could use it full-time at work– documentation is forced to improve by an expanding community– and (b) people who were using it weren’t forced, by external circumstances, to waste so much time justifying using the best tools instead of the industry-standard ones.
Also, Haskell documentation suffers from the uneven educational levels of people who come to it. It’s not as tough as its reputation (you don’t need a PhD in type theory to understand it) but it is a hard language to get good at. Because of the steep learning curve [1] and the brain-rewiring that the language involves, it’s very hard to write documentation that reaches all levels. This is a problem that a less substantive and less powerful language/culture like Java (at least, typical enterprise Java) doesn’t have.
[1] Note: literally speaking, a steep learning curve is a good thing. It’s arduous but rewarding.
We’d have great documentation in Haskell if (a) more people could use it full-time at work– documentation is forced to improve by an expanding community– and (b) people who were using it weren’t forced, by external circumstances, to waste so much time justifying using the best tools instead of the industry-standard ones.
This is a lame excuse. Haskell packages are often missing a “getting started” example, and most functions and types then don’t even have a one sentence description.
Also, Haskell documentation suffers from the uneven educational levels of people who come to it. It’s not as tough as its reputation (you don’t need a PhD in type theory to understand it) but it is a hard language to get good at. Because of the steep learning curve [1] and the brain-rewiring that the language involves, it’s very hard to write documentation that reaches all levels. This is a problem that a less substantive and less powerful language/culture like Java (at least, typical enterprise Java) doesn’t have.
I think Haskell has a problem with its lore of Exceptionalism. The Haskell community is not exceptional in the sense that it has fallen for Exceptionalism, other communities have suffered from exceptionalism as well - and it did not do them good (remember Scheme?). What do I mean by Exceptionalism? It is the idea that one is so different from “the others”, that one does not have to play by their rules
In the haskell community, a great emphasis lies on the benefits of the type system. Which is taken as an excuse to avoid documentation, unit tests and descriptive identifiers. No documentation? The type signature is documentation enough! No unit tests? The type checker rules out most bugs anyway. For each of these points, there is a certain benefit in Haskell that supports them. The type system indeed rules out some classes of bugs, the type signature indeed gives some information that would in other languages only be communicated in a documentation string, and haskell syntax lends itsself to terseness. The issue with exceptionalism is, that the exceptionalist push simple benefits too far.
The notion that Haskell is exceptional for its high educational level is an easy argument, yet I would like to ask what educational level is present in other communities? Our industry is full of formally educated people and self-tought people. Python/Java/Clojure documentation also have to bridge gaps between different levels of experience. And it is quite simple. You write some paragraph that is accessible for people of all backgrounds, and another paragraph that is specifically targeted at the experts. Or: You write a reference manual targeted at experts and a users' guide for people without much knowledge.
Another interesting aspect about the lack of documentation in Haskell is, that with pure functions and side-effect free code, documentation should be so much easier that for a stateful, procedural Python library. With side-effect free functions, two lines of example code showing what a function evaluates to when being fed with appropriate input should often be enough to get you going, yet I often see this is lacking in Haskell packages.
So to this day, Haskell is an environment for experts, but not a professional environment. You cannot blame companies for not bringing your expert-environment into production and turning it into a professional environment. It goes the other way.
PS: while this comment might appear to be a rant, I actually do like Haskell as a language and I think amazing software is produced by the Haskell community. So I would like to see Haskell get into a shape that I would be confident to suggest using at work.
The one bit I disagree with is:
Avoid TemplateHaskell
I don’t understand the hostility to TH, but I’ve never needed it to solve my own design problems, just leveraged other peoples' so I don’t have any boilerplate. I like that it’s there, as an option, in case I change something. OTOH, I was a Lisper before. I’ve not really minded macros and having them in a typed language is really nice.
I’ve copied and pasted the code TH generates and prettified it to bring compile times down before too. Love a tool to automate that.
There’s a few annoying thinsg about TemplateHaskell. One is that it gives another way for the semantics of your Haskell program to change based on syntax. One existing way is deriving Ord, which relies on the order of constructors in your source code:
data O = A | B | C deriving Ord
-- A < B < C
Which prevents refactoring (I might change the order and bang, now my program breaks) - TH is so powerful that it allows this to apply to pretty much anything. We need better tools, e.g. I would like to see a version of TH which allows you to state what refactorings are destroyed and which are preserved.
I’ve copied and pasted the code TH generates and prettified it to bring compile times down before too. Love a tool to automate that.
And this would be another tool. In the above, I’d copypaste the Ord instance and now I can refactor without problems. Same for TH.
The main way in which I’ve had generics or TH ruin my day, it’s been anything serialization related. JSON derived from TH or generics is scary, but it’s not much worse than what dyn-langers do.
If we ask the more foundational question of why Generics can’t be used for these tasks and we’ll arrive at answers about shortcomings in GHC or flaws in abstractions. Bolting crap onto the language using metaprogramming hacks is convenient sometimes, but it isn’t the Haskell way of striving to do “the right thing”.
I agree with 99% of what’s being said here.
The one bit I disagree with is:
There’s one case where I think TH is a win: to auto-derive lenses (e.g.
mkLenses). Of course, you’re not writing your own Template Haskell when you do this. That said, if you’re used to Clojure macros, and new to Haskell, you should follow this rule. It’s extremely rare that you need to use TH, especially withGHC.Generics. Virtually every case where you’d want to use TH has already been covered by a library. Also, Haskell does a lot of extremely sophisticated stuff (e.g. fusion) that makes the performance argument behind macros in Lisps meaningless. (Yes, I’ve seen Common Lisp programs that used macros for performance. With GHC, that kind of thing should never be needed.)True, but I think that it’s actually very good relative to the size of the Haskell community and what this entails sociologically. When I tried to build up a Haskell presence at my last job, I had to spend so much time justifying the use of Haskell (that is, playing goddamn politics) that I got a sense of what it means to be fighting for your life. Haskell has a small community of besieged, elite engineers who have to fight off “Why aren’t you just using Java?” mediocrity from all angles. It’s not surprising that the quality of documentation wouldn’t be at, say, the Python or Clojure level.
We’d have great documentation in Haskell if (a) more people could use it full-time at work– documentation is forced to improve by an expanding community– and (b) people who were using it weren’t forced, by external circumstances, to waste so much time justifying using the best tools instead of the industry-standard ones.
Also, Haskell documentation suffers from the uneven educational levels of people who come to it. It’s not as tough as its reputation (you don’t need a PhD in type theory to understand it) but it is a hard language to get good at. Because of the steep learning curve [1] and the brain-rewiring that the language involves, it’s very hard to write documentation that reaches all levels. This is a problem that a less substantive and less powerful language/culture like Java (at least, typical enterprise Java) doesn’t have.
[1] Note: literally speaking, a steep learning curve is a good thing. It’s arduous but rewarding.
This is a lame excuse. Haskell packages are often missing a “getting started” example, and most functions and types then don’t even have a one sentence description.
I think Haskell has a problem with its lore of Exceptionalism. The Haskell community is not exceptional in the sense that it has fallen for Exceptionalism, other communities have suffered from exceptionalism as well - and it did not do them good (remember Scheme?). What do I mean by Exceptionalism? It is the idea that one is so different from “the others”, that one does not have to play by their rules
In the haskell community, a great emphasis lies on the benefits of the type system. Which is taken as an excuse to avoid documentation, unit tests and descriptive identifiers. No documentation? The type signature is documentation enough! No unit tests? The type checker rules out most bugs anyway. For each of these points, there is a certain benefit in Haskell that supports them. The type system indeed rules out some classes of bugs, the type signature indeed gives some information that would in other languages only be communicated in a documentation string, and haskell syntax lends itsself to terseness. The issue with exceptionalism is, that the exceptionalist push simple benefits too far.
The notion that Haskell is exceptional for its high educational level is an easy argument, yet I would like to ask what educational level is present in other communities? Our industry is full of formally educated people and self-tought people. Python/Java/Clojure documentation also have to bridge gaps between different levels of experience. And it is quite simple. You write some paragraph that is accessible for people of all backgrounds, and another paragraph that is specifically targeted at the experts. Or: You write a reference manual targeted at experts and a users' guide for people without much knowledge.
Another interesting aspect about the lack of documentation in Haskell is, that with pure functions and side-effect free code, documentation should be so much easier that for a stateful, procedural Python library. With side-effect free functions, two lines of example code showing what a function evaluates to when being fed with appropriate input should often be enough to get you going, yet I often see this is lacking in Haskell packages.
So to this day, Haskell is an environment for experts, but not a professional environment. You cannot blame companies for not bringing your expert-environment into production and turning it into a professional environment. It goes the other way.
PS: while this comment might appear to be a rant, I actually do like Haskell as a language and I think amazing software is produced by the Haskell community. So I would like to see Haskell get into a shape that I would be confident to suggest using at work.
I don’t understand the hostility to TH, but I’ve never needed it to solve my own design problems, just leveraged other peoples' so I don’t have any boilerplate. I like that it’s there, as an option, in case I change something. OTOH, I was a Lisper before. I’ve not really minded macros and having them in a typed language is really nice.
I’ve copied and pasted the code TH generates and prettified it to bring compile times down before too. Love a tool to automate that.
There’s a few annoying thinsg about TemplateHaskell. One is that it gives another way for the semantics of your Haskell program to change based on syntax. One existing way is deriving Ord, which relies on the order of constructors in your source code:
Which prevents refactoring (I might change the order and bang, now my program breaks) - TH is so powerful that it allows this to apply to pretty much anything. We need better tools, e.g. I would like to see a version of TH which allows you to state what refactorings are destroyed and which are preserved.
And this would be another tool. In the above, I’d copypaste the Ord instance and now I can refactor without problems. Same for TH.
The main way in which I’ve had generics or TH ruin my day, it’s been anything serialization related. JSON derived from TH or generics is scary, but it’s not much worse than what dyn-langers do.
If we ask the more foundational question of why Generics can’t be used for these tasks and we’ll arrive at answers about shortcomings in GHC or flaws in abstractions. Bolting crap onto the language using metaprogramming hacks is convenient sometimes, but it isn’t the Haskell way of striving to do “the right thing”.
For those looking at the where to start link in the post, here is the more up to date github repository.
I really like these git document collaborations that document the best libraries or methods for a language.
I’ve made an (opinionated) Haskell library recommendation listing. Haskell tooling recommendations here.
As for where to start, I’ve maintained a guide for learning Haskell which recommends free resources for awhile now. If you’re willing to pay, I’ve been working on a Haskell book with my coauthor Julie. If you can’t afford the book, please ping us. I also wrote the Haskell HowIStart tutorial and used CSV for the example.
I wrote a short post if you want a quick-n-dirty example of translating Python into Haskell.