Reflecting on Haskell in 2016
stephendiehl.com
stephendiehl.com
One of the small bumps I had was getting my environment setup. Based on my experiences with Ruby and Node, I knew I'd want to have a tool for managing the language's version and dependencies per-project, so I ended up going with stack [0]. Arriving at that decision required a bit more reading than with other languages. Additionally, while setting up stack, I thought their docs were too long. They'd benefit from being broken up into more pages, instead of pushing so much all at once. With that said, the information presented in the docs is actually quite clear and well written.
Looking at the Downloads section [1] on the Haskell website, it looks like they've improved the docs since I last visited, but it's still a bit confusing. What's the point of Haskell Platform? It looks like it includes stack, which already covers all my requirements. Maybe it'd be useful to include a "why" section for each choice, to provide some examples of scenarios in which you might go with one choice over the other. Telling me what I'm getting doesn't give me any meaningful information if I don't know why I'd want that in the first place. I think there's too much information up-front, even though people landing there probably aren't equipped to make use of it. Why would someone pick the Haskell Platform option or the minimal install option?
While reading Learn You a Haskell, I used Haskell for Mac [2] for poking around. It's pretty great, although I didn't end up purchasing it, as I'm not doing anything that would benefit from using it.
Something I liked about Elixir is that you can just read their getting started docs and pick up Phoenix framework to get a web app up and running. That gives you a nice base on which to gradually build upon as you learn. Does anyone have a similar suggestion for Haskell?
[0] https://docs.haskellstack.org/en/stable/README/
I recently got a new machine and decided to try _only_ using stack. All I had to run to get started was
$ curl -sSL https://get.haskellstack.org/ | sh
The advantages of stack are that: * I have an easy upgrade path for GHC (no need to install or uninstall) - I just change the global resolver
* I can have multiple GHC versions installed at once (great for debugging)
* getting rid of old versions (to clear up space) is just deleting a folder
* most of my dependency problems get solved by resolvers
The only downside I've encountered so far is that building GHC itself is quite finicky with this setup. Unlike the Haskell Platform, I will have to install manually the libraries I need - that makes development offline quite tough (you find yourself without internet and without the library you need installed).That aside, one good starting point for building up Haskell is the 99 problems [1]. Haskell is more general purpose than Elixir, so past that, it really depends on what you want to do with it.
[1] https://wiki.haskell.org/H-99:_Ninety-Nine_Haskell_Problems
why do you say so? elixir seems pretty general-purpose...
The opinions kind of break down as:
1. Simply get GHC on their machine - Typically academic instructors trying to get their students started with low overhead. They simply want GHC and GHCi available so an assignment can compile, or code can be tested in the repl.
2. Install Haskell Platform - This has been strongly supported by what I would call the older Haskell community, although admittedly share your confusion as to its point. This seems to target point-and-click users and give them every tool in the ecosystem so that when they reference the random blogs/documentation out there they aren't confused by missing a command.
3. Use Stack - This has been heavily pushed by people trying to help Haskell grow in the programming industry. It's a fantastic tool and I recommend everyone use it if they plan on doing complex projects, especially in a team setting.
My hope is that over the next year or so we'll see more stack adoption, ideally because there are more consistent tutorials/guides/documentation published which target it as the basic tool to start developing Haskell in.
[1] https://www.reddit.com/r/haskell/comments/50prvg/haskellcomm...
1. I feel like there is a really strong push towards writing concise code, which make it really hard to approach for me. I've seen a lot of code which substitues words as function names for 2 or 3 character symbols. I'm okay with learning `>>=` and the like, but when every library want to invent its own symbol-functions, I feel like the barrier to entry for me becomes much higher. This occours in just about every high profile library I've seen, from parsers to web frameworks; everyone wants to invent their own DSL.
2. For as much as Haskell seems to pride it self on function composition I don't think `.` is the best way to do so; Clojure's threading macros are much more readable to me. Comparing the thread-last macro ``` (->> (range 10) (filter odd?) (map #(* % %)) (reduce) ``` to Haskell's composition operator `(sum . (map (\x -> x * x)) . (filter odd)) [1..10]`. (Please correct me if there is a clearer way to write this.) The former is much more readable from and LTR English language PoV. In Haskell I need to start from the right and work my way left; and this become even more harder for me to decipher when function operator precedence starts coming into play. It's small quality of life things life this which makes all the difference IMO.
3. The millions of syntax extensions in ghci, some of which are incompatible with each other. This means ProjectA and ProjectB can be written in completely different, possible incompatible, 'dialects' of Haskell. Now I have to learn the base Haskell languge and whatever language extensions that project has dedcided to use just so I can start reading and understanding the code.
4. AFAIK, there is now easy way to get function documentation in the repl. Sometimes types aren't enough for me and I would like to have some human written documentation guide me when I'm trying to use a library.
sum $ map (^2) $ filter odd [1..10]
Or, defined as a function: > let foo = sum . map (^2) . filter odd
> foo [1..10]
165
You can write it without using the composition operator at all, if you prefer: > let bar xs = sum (map (^2) (filter odd xs))
> bar [1..10]
165
In general, you can write out your programs as crazy sequences of operators (whose precedence may not be obvious to the reader): > take 5 . unfoldr (Just . next) <$> getStdGen >>= putStrLn . show
[1336079013,234736121,108049288,410228860,1573295749]
But you don't have to: > let infiniteRandoms = unfoldr (Just . next) :: StdGen -> [Int]
> gen <- getStdGen
> let fiveRandoms = take 5 (infiniteRandoms gen)
> putStrLn (show fiveRandoms)
[1336079013,234736121,108049288,410228860,1573295749]
People seem to think Haskell is all about writing your whole program in a single hideous line of code with incomprehensible sequences of arcane operators glued together by a glut of anonymous functions, but that's just bad code.As for left-to-right vs right-to-left, I have never had a problem with the way Haskell does it. I think if you're coming from a language that does it differently, it makes sense that Haskell would trip you up in that regard. Haskell's composition operator matches the way it's usually written in mathematics, but there's nothing special about it and you could change it to go the other way if you really wanted to (but please don't):
> let g . f = \x -> f (g x)
> let foo = filter odd . map (^2) . sum
> foo [1..10]
165
`(>>>)` from `Control.Arrow` is a more reasonable way to get that sweet left-to-right action but using it might still throw people off: > let foo = filter odd >>> map (^2) >>> sum
> foo [1..10]
165In math, the preferred way of writing functions is via composition, as then it enables tools of visualization such as commutative diagrams. One thing to note is that in general mathematicians have a history of picking the right choice in notations for thinking about abstractions at an intuitive level in the world of mathematics (when there is a choice and it matters), and IMO they were correct about how they chose to represent function composition, although it is not immediately obvious unless you start talking about function domains and ranges - the composition notation matches the flow of reading how functions map values from one set to another.
That Clojure version reads like a complete mess to me personally.
For short chains, pronouncing `.` as "of" works well in English, e.g. `sum . tail $ foo` is "the sum of the tail of foo`, and it follows the same order as nested function application: `sum (tail foo)`.
I agree the the other way around, e.g. a "then" operator `>>>`, is easier to understand with long chains: with `f . g . h . ...` we have to remember `f`, `g`, `h`, etc. in a "mental stack", until we get the the end. With the other way round, `... >>> h >>> g >>> f` we can "mentally apply" each function to a "mental accumulator" as we encounter it.
sum . map (\x -> x * x) . filter odd $ [1..10]
Function composition leads to a very stable right-to-left syntax. It also takes some practice, but in Haskell you almost never have to go hunting for operators or remember if something is infix or prefix (except for the shameful single argument '-', as in '-1').To my knowledge, there are no GHC extensions that are incompatible on a project level (that is, you could have one enabled in one file, another enabled in another, and it would break things). I'm much less confident that there are no extensions that are incompatible if you try to use them within the same file, but I am not able to think of any off the top of my head.
Stack creates reproducible builds (AKA frozen dependencies), but instead of you freezing everything, the community creates some frozen sets for you, and you choose one. That avoids the dependency hell that happen on other environments when your dependencies list gets big.
Cabal is much more like a run of the mill dependency management system. You'll declare everything in the usual way, it will resolve the dependencies (in a much better than usual way, but still looks like everything else), and make them available for you.
Both systems can manage dependencies globally or in a project by project basis.
I've found that for creating libraries and publishing them on hackage one is almost certainly better off with bare cabal. For creating binaries for distribution, one is almost certainly better off with stack.
About installation, every road will take you to a system with at least ghc, and cabal. Getting stack too is very desirable. I've found that on windows it's easier to run the stack installer, and install everything from it. On Linux it's easier to compile (yes, it's that bad) your own GHC and cabal, and get stack from cabal. The Haskell Platforms looks to be meant to distro package maintainers - I have never had good results from trying to install it from the site.
I had no issues setting up my dev environment with stack on Ubuntu 16.04 as documented on haskellstack.org. What Linux distro do you use?
I've installed GHC from binaries more than once without a problem, same for cabal. But I've concluded it's not reliable.
I don't really write much haskell - but last I checked, the "howistart.org"-article seemed reasonable:
http://howistart.org/posts/haskell/1
I think it's actually harder to figure out how one (should) start with python an venvs than it is to "find" a reasonable approach for haskell.
Just a bit frustrating.
However, I find your tone particularly unpleasant. The sneer in "seem to be people who need worked examples of things to understand them" is repulsive. If this is a representative example of your community, it's one no-one should be proud to be a member of.
[1] http://www.maa.org/external_archive/columns/launchings/launc...
Its always good to apply the principle of good faith. You have no idea who you're talking to, are likely going in biased away from someones arguments, and this will be the first time you've ever conversed. On top of that you're hobbled by text. You also don't know if the writer is a native english speaker or not and might consider the phrase "seem to be people who need worked examples of things to understand them" entirely neutral in tone.
Communication is a 2 way street, the tone you perceive may not have been intended. And painting an entire group by one sentence, in one post, that you perhaps disagree with, is a bit of an overreaction in almost any circumstance. The tone you perceive is not one I've personally experienced, quite the opossite.
As a beginner in Haskell that is still learning, and learns best by examples, the gp's opinion on documentation drives me nuts. But by and large, most examples aren't all that necessary in haskell with the type system. But when you're learning, I have to say, I hate "the types will document everything" mindset. They tend not to when you're a stranger in a strange land.
I wouldn't say documentation itself is a problem in haskell, there is tons. I would say the problem is in quality documentation that at least recognizes audiences of disparate skill level would be at issue. Examples help, but if the examples use something like the state monad that you're not familiar with, it probably won't do you a lick of good to understand how to use it.
Haskell is hard to learn, or at least it was for me. There is a whole laundry list of concepts I had never even heard of that I had to understand before I could do anything real with the language. Some were apparently dead simple yet frustratingly abstract (e.g. Monoids). Some were intuitive but still took time to grok (e.g. list manipulation stuff). Some twisted my brain into knots and only yielded to persistent study and practice (e.g. monads with threaded state).
As I was working through all these "basics", I was constantly frustrated trying to write simple programs. I don't recall whether I blamed it on a lack of beginner-friendly documentation or not, but slowly it all started to resolve into a coherent picture and once I could consistently read and understand real-world types I found that the available documentation was almost always enough for me to quickly understand an interface and how to proceed in using it.
I think both sides of this debate are partly right. Haskell's learning curve seems to keep going up as far as you want to climb, and some of the stuff at the intermediate level IMO could really use more examples and documentation, or at least that was my opinion when I was looking at it a year or so ago. One good example might be Template Haskell, which pissed me off to no end every time I tried to use it even in very simple applications. It involves a lot of new syntax and concepts and IIRC had literally no documentation besides what Haddock gives you for free.
On the other hand, I think a lot of people criticize Haskell's documentation without knowing the language well enough to make use of said docs or even understand how they might be useful. IMO it's unrealistic to expect every module and library to provide documentation specifically for beginners who don't understand challenging yet ubiquitous concepts (like state monads, to use your example), and I don't think other languages necessarily do a better job at this, but Haskell is just so darn tricky to get your head around that the "total beginner" phase lasts way longer than it might in e.g. Python.
For beginners who do want to learn about the core concepts of the language, I found that there was plenty of material to help me on my journey: Real World Haskell, LYAH, the IRC channel, and the internet full of blog posts, to name just a few. I don't mean for this comment to cause offense, or to belittle anyone. I'm certainly not an expert Haskell programmer, and there is much that I still don't understand about it. I just wanted to share some insights I've had learning it and using it in some practical applications.
Counterpoint: this is what keeps me away from Haskell.
I really want to learn, and I really do appreciate the formal approach, but being able to do a few simple things quickly (driven mostly by intuition) helps fight frustration.
Haskell really does look great, but it's a bit... prickly.
Disclaimer: I'm very much a Haskell noobie
No, but for this case, type holes are much more powerful. You always have an I have X, I want Y, what functions are there that are X -> Y?
Hoogle is more powerful than anything I've seen on any other language. (If I could only make it use all the local packages, instead of the pre-built index. I'm sure there's a way.)
Haskell has also more need for documentation than most other languages, so hoogle is still not enough. That's the problem, not lack of docs.
Python, PHP, etc... are incredible in that every single page of their standard library docs have fully worked examples. When you're trying to get things done, it's great to have a foundation to start from and see how others have done something.
I think most documentation sucks and I dislike trying to read it, because it's very hard to get a picture of what's going on, and what these procedures / data structures / etc are really for.
I am much happier when I can just look at a straightforward and clear example, and then just use the documentation to look up specifics of how things work after I already get the basic idea.
It's not because I "need worked examples of things to understand them", it's because that is the way I like to work, because I have had many instances of my life of trying to make sense out of documentation that seems to have been written from a mindset of "formal writing involves not actually telling the reader what things are really for, straightforwardly". I don't know why that disease is so common, but almost all documentation is like that.
I'm not, especially for the many more-abstract-concepts. I have yet to see a followable code case demonstrating the use of custom monads (not IO or Maybe or lists etc) that show why (when) I should ever write my own, to understand even just using them better generally.. A lot of explanations in the Haskell ecosystem are super-abstract and forever-self-referencing and as someone arriving with a sense of urgency of pumping out Brave New Apps to the world, I'm always itching and saying "OK transformables turn foldables that contain applicatives into functors that fold applicatives into transformables so in other words I CAN SKIP THIS RITE?" Leave it in the shadows as it was clearly a priority to neatly have the abstractions that allowed making MayBe/IO/Lists etc as usable language features in there.
On the other hand I don't want to end up writing 10k lines that could have been expressed in 500 had I grasped the more obtuse abstractions.
Experience tells me that once you happen across a simple real-world use, the shocking simplicity of what was encrypted in mathematical-logical-calculi lingo is instantly revealed. The absence of such "code examples" (with a real-world touch, not just x,y,z,f,g,h identifiers in a senseless vacuum) is truly annoying and goes all the way from the Wiki to Diehl's articles to various books.. it's hyperprevalent throughout the community.
For an interpreter I'm working on I have an "Eval" type, implemented as a newtype wrapper around a transformer stack. This gives me a context to work in where I can access variables in scope (carried in a ReaderT) and fail with error (handled by an ExceptT). The code (simplified) looks a little like this:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaExpr #-}
newtype Eval a = Eval (Reader EvalContext (ExceptT String m) a)
deriving (Functor, Applicative, Monad, MonadReader EvalContext, MonadError String)
lookupVariable :: Variable -> Eval Value
lookupVariable v = asks (findVarInContext v) >>= \case
Nothing -> throwError ("unbound variable: " ++ show v)
Just result -> pure result
lookupFunction :: FunctionName -> Eval ([Value] -> Value)
lookupFunction f = asks (findFuncInContext f) >>= \case
Nothing -> throwError ("unknown function: " ++ show f)
Just f' -> pure f'
evaluateFunction :: Function -> Eval Value
evaluateFunction (Function name args) =
lookupFunction function <*> mapM evaluateExpr argsI must admit that I can't remember ever creating my own monad from scratch.
Well sure, but if we're going to exclude those then the grandparent's ask is a bit high: either we present something useless and pedagogic, or we present something useful that exists in a library somewhere, or we present something new and useful... that we should then also put in a library somewhere!
I do notice that after a while, I can get more and more from types alone, but I would never get to that point without examples first.
----
I don't see why examples couldn't be type-checked though, so they never become out-dated – is there no way to do that with haddock?
That's completely baffling to me so I'd be really curious to hear your reasons (or those of someone who shares that opinion, as there are others in the thread apparently).
When learning about an abstract notion, it has been my experience that having good examples in mind (in the sense that they are not too complex, but non-trivial enough to illustrate the relevant aspect of the notion at hand) is very helpful, if not essential, for comprehension. All the more so for very abstract subjects (e.g. back in grad school I was studying algebraic geometry, and you can't go very far in that subject trying to prove things about functors on the category of rings without examples in mind that connect the abstract nonsense to some actual geometric meaning).
Speaking of abstract nonsense, by the way, under the Curry-Howard isomorphism, publishing a library with type signatures but no worked out example is equivalent to publishing a mathematical paper consisting entirely of lemmas with no example of how to combine them to prove something interesting (in fact, it's worse, because the expressiveness of the Haskell type system obviously pales in comparison to the language of mathematical papers). I would almost certainly reject a paper like that if I received one for review, and I expect most referees would too.
I suppose what people who are curious about Haskell find lacking are definitive language guides like the Rust Book, Effective Go, and the like?
It's all in all a very bad way to do polymorphism and that's what the article points out. It's especially odd in a language like Elm, that obviously is supposed to be like other ML-like languages.
After using the language for two years I find that the types are actually enough to understand a new library, however, am taking for granted that it's an acquired skill.
Looking back I do recall being in the same position as you, someone who just wanted to wrap their head around something and get an example working. I was stubborn and plowed through things I didn't understand until it clicked, but do realize that not everyone is as hard headed as myself.
So my basic impression is: as soon as you know where the library fits in and how it works and even more importantly why it is doing things the way it does, you can get by just by using type signatures. But that knowledge is usually hidden behind a myriad of half-done blog posts and well-meant tutorials, which introduce you to the what but still assume a good deal of knowledge about why. And the rabbit hole gets larger with every dependency boiled onto your actual study target.
It's not by any means impossible to get in, but I think it could get a lot better. Just making a habit of merging tutorials and introductions into the module's documentation would be a great step forward. A mandatory ELI5 section might do wonders :)
I think this overstating it, unfortunately. I'm an intermediate Haskeller, and when I tried to use `hasql`, I found the lack of documentation to slow me down.
It's a testament to the power of types as documentation that I was able to use it at all, but examples and simple cookbook-style "Here's how you do this thing" or "Here's how you use this component" or "You can't do this because the interface doesn't allow it; here's why" would have sped up my acquisition of the library immensely.
Exactly.
Quick, tell me what this function does:
foo :: Num a => a -> aIt's basically Haskell code smell. Other languages we are used to do not allow exact precision when talking about input and output types, that's why we don't think about overly-generic function declarations as smelly, but they are.
Types can be a useful part of the documentation, but if your program is the least bit interesting, you will have parts that you should properly document. This is so much more true for libraries, especially those that adhere to a more mathematical style. If you write such a library, you should also write a paper explaining the library.
words :: String -> [String]
If you say it's already obvious, I disagree, since this code prints "1": main = print $ length $ words "jack am I"
(The spaces in the string are six-per-em unicode characters)In this case, I'd try something like this:
words :: Sentence -> [Word]
(Sentence and Word being aliases for String)A function named `words` with `Sentence` as a parameter implies a common-sense do-what-I-mean function, like breaking on all sensible whitespace. With common sense in play, it's your task to make the function behave like people expect it to (which differs per person of course). If you choose not to, don't write `words`, write a `split` with a parameter for character classes (or indeed a boolean function working on a character) the split should be performed on.
(PS. I assume you are implicitely critisizing Prelude's `words`, which breaks on anything that's `isSpace`, which is explicitely defined. Its definition is way out of my competence, there are probably good reasons for not including thin spaces. If not, they could probably get included with a due process -- with common sense, it's always an iterative process till it's done)
You're never given only the type signature however, you also will have the source code. It's very likely that foo is no more complicated than something like:
foo :: Num a => a -> a
foo n = n * 42 + 1
If foo is as complicated as that, then a sentence or two explaining what it's purpose is would be helpful; explaining the "why" of such an odd function would be good. The documentation probably can't say "what" foo does any more clearly than the source code however.If the function is reasonably named, like:
double :: Num a => a -> a
double n = n + n
then having some documentation that says "Doubles the given number" isn't going to add much value, and might become out of sync with the actual code. I appreciate that all the Haskell documentation I have ever encountered has a links to the source code throughout.Aside: When I look at the definition of an unknown function in Haskell, I feel like I'm at the top of an hierarchy. The unknown function may be comprised of other unknown functions, but the entire structure of what is happening is present. I know what all the variables are, etc. When I look at the definition of an unknown object-oriented function I often find myself in the middle of an inheritance stack with implicit behaviors and variables being inherited from above, and unknown functions being called below, and it's more confusing in my opinion.
So the type claims. Without looking at the implementation or using `-XSafeHaskell`, you don't know if there's an `unsafePerformIO` call lurking.
/pedantry
So within the context of this thread, type signatures vs hand written documentation, I would say your point is a +0 for hand written documentation. Both type signatures and hand written documentation can lie.
foo :: (BarMonad m, BazApplicative b) => ConfigurationStructure t -> (b -> m t) -> [b] -> t
You can figure out a little of what it does, but how that fits into the application it supports, and what exactly it should be used for is non trivial.Haskell programmers (whose numbers I count myself amongst) saying that "the types are the documentation" is like expecting someone to build a lego model from the picture on the box, and saying "well the studs are the documentation of how the pieces fit together". It's correct, but it misses all the nuance of how the functions should be composed, not just how they can be composed.
http://softwaresimply.blogspot.com/2016/12/on-haskell-docume...
I think it's just that the gap to get proficient with Haskell for an imperative programmer is a hurdle they are blind to (I was blind myself!), and they assume a few simple tutorials will bootstrap them into the language like it did the other handful they learned.
This is clearly an education problem, but I guess we still have a ways to go to get acceptance.
Yeah, my intent wasn't to suggest that all non-haskell docs suck. But to show how other languages are much more howto/tutorial oriented, which I didn't appreciate as much before I had to look at ACE recently.
As an example, the single kind off complex library I created (called "interruptible") is still lacking a good explanation of what it is good for, because despite having created it to solve a specific problem of mine, I still could not find a good way to explain it.
As an example, I was doing some password hashing stuff a while back. The most popular Python library had horrible docs where all the arguments were strings and it was ambiguous what exactly went where. The Haskell library had almost no prose docs, but the type signature was something like
Password -> Salt -> Difficulty -> HashedPassword
Literally impossible to mess up.Personally, I'll take Haskell type-based docs over any other extant documentation that I've come across. Learning to read types effectively and quickly is a bit of a learned skill, but it comes naturally with a bit of use of Hackage or Stackage.
Also, Haskell has services like Hayoo or Hoogle where you can come up with a type signature and it will tell you anything that had that signature. Like let's say I want a function that goes through a list of maybes and returns them all if none of them are Nothing. I just search for
[Maybe a] -> Maybe [a]
I get "sequence", which is the correct answer. Good luck doing something like that with the Python or Java docs.> why there hasn't been more uptake of Haskell for all of the apparently cool ideas that are there,
People already know how to get the job done one way or another and learning new stuff is hard. It's an unfortunate but pragmatic viewpoint for many people.
Moreover, it's documentation that's immediately available for the expression I just assembled at the repl!
None of which is to say most of us wouldn't love some good, correct documentation. But that takes a lot of effort, and I can see why priorities wind up being elsewhere given that it's a smaller improvement over what's available free than in other languages.
Worked examples are actually low-hanging fruit that we really should be making available, given that we can mechanically ensure correctness. Come to think of it, I wonder if this could just be a matter of surfacing existing end-to-end tests somewhere visible.
Now, I find it very hard to believe that you’ve never heard of a practical use for Haskell. Do you just not care about the things that companies are using it for? (Compilers, web apps, backend services, finance, educational apps…)
I can only think of "darcs" which for all intents and purposes was a failure. IIRC, one of the darcs retrospectives I've read, pointed out that GHC runtime behavior and its hard-to-foresee and hard-to-measure complexity properties, was a problem.
Moreover, another high-profile failure that springs to mind, is Joel Reymont (wagerlabs.com) trying to write a high-performance poker server in Haskell and eventually abandoning it in disgust due to non-predictable behavior of the GHC runtime. He delivered it (with assorted paeans) in Erlang instead, which proved quite lucrative for him.
I used Haskell for 2 years during my undergraduate degree, for program analysis. It was a good choice for such a theoretical domain. Some time later, I had another look at applying it to more practical problems. Besides the slight turn-off due to cultish behavior - which is also obvious in this thread, many posts excuse the lack of documentation or posit it as not a problem (!?), if not outright exalt it! - I got from the community itself, the language felt completely sterile and - most importantly - not fun. The syntax is also atrocious.
I concluded that if static typing was needed, I would pick ML every single time over Haskell. I also have no affinity with Haskell's type system (in the sense that it leads to better programs) or its interactive nature (laughable compared to Lisp/Smalltalk). I also remember something Sussman said, "Haskell is the most advanced of the obsolete languages" [1], and can't help but chuckle.
[1] https://www.infoq.com/presentations/We-Really-Dont-Know-How-...
How about pandoc, PostgREST, git-annex, the Elm compiler?
You can find more examples here: https://github.com/Gabriel439/post-rfc/blob/master/sotu.md
https://skillsmatter.com/skillscasts/4251-lenses-composition...
That said, it's not just use. You've also gotta deal with some additional imports, and with defining your lenses. For the simplest case, that's a bit of overhead compared to having it all baked in.
There is active work done by Adam Gundry to extend this even further [1]. The key part of this is that there will be a new type class so that I can express as a constraint that a type must have a field with a certain name and with a certain type.
Further in the future, but still actively discussed is using overloaded labels as lenses [2]. Past that, I can't imagine anything else I would want records to do.
[1] https://github.com/adamgundry/ghc-proposals/blob/overloaded-... [2] http://stackoverflow.com/questions/38136144/replace-record-p...
You may be alright with vanilla Haskell records now that duplicate record fields are allowed in GHC 8.
I think something like rawr[1] might be what most are looking for when talking about better Haskell records, though.
0: https://hackage.haskell.org/package/vinyl-0.5.3/docs/Data-Vi...
1: http://hackage.haskell.org/package/rawr-0.0.0.1/docs/Data-Ra...
There's a pile of packages like diagrams (http://projects.haskell.org/diagrams/) or yesod (http://www.yesodweb.com/) which have tutorials, examples, books. People who have been working mainly with these should be completely expected not to feel much of a problem with the state of documentation.
There are also packages which have mostly/only API information. Sometimes, this tells you everything you need to use a package effectively. Sometimes it doesn't. And this is impacted substantially by people's level of skill -- at Haskell and at inferring usage from names and type information in particular.
There's room for people to have very different experiences
This sounds kinda off-putting, but I'm not totally sure what it means. Are the SQL libraries for haskell comparable to e.g knex, or psycopg, or sqlalchemy? The bit about string interpolation makes me think that prepared statements aren't used?
I don't want to be picky but if you're writing something public, learn how to use your language right.
Neither do I, but there should be a comma before the "but" there.