Hacker News new | ask | show | jobs
by nitrix 3571 days ago
A few incorrect points during the discussion as well as poorly approached. The only thing beneficial that I see from it is people trying to better their skills and Haskell gaining traction.

I personally would recommend #haskell-beginners on freenode IRC as well as http://haskellbook.com for the ones interested.

For everybody else, well I'm not a sale person and my job isn't to convince you. If it takes you 30 years to (re)discover Haskell, so be it.

3 comments

Haskell has been around for over 20 years. If it hasn't set the programming world on fire yet, there are probably reasons.
Haskell as we know it now, with high performance, large library selection, more powerful type system, advanced tooling, testing and profiling etc, has been around for significantly less time than that.

I also think that's a specious argument. Many things influence a language's popularity that have nothing to do with the language's actual value. Haskell is very idiosyncratic compared to other mainstream languages, requiring a "relearning" of a lot of skills developers take for granted. Many people balk at the learning curve and never get into it. Haskell has also received comparatively little contributions from industry and was never the pet language of a major organization (like e.g. C#, Java, Go, Rust, Dart, etc). Also the influence of Haskell can be seen in a variety of areas, from other languages adopting more advanced type systems, type classes, systems like LINQ in C#, and the increasing popularity of functional programming in general. Finally, although popularity drives language ecosystem and therefore usability, Haskell's merits purely as a language stand on its own regardless of how many people use it.

The good haskellers I've talked to about this say Haskell has only recently become a mature language=)

The modern fast data structures packages date from 2007 to 2011 (containers, vector, text, and unordered-containers).

Recently there have been more breakthroughs like FB adoption and an unrivaled web API library in Servant (https://haskell-servant.readthedocs.io/).

Also we got Stackage and Stack recently (which ended "cabal hell"). Even "cabal hell" is gone with the new cabal-install improvements.

So don't count Haskell out too easily because it's old. It's an awesome language, but it took people a long time to figure out how to program well in it, given that it's so different from the normal way of doing things.

Like we only now see how bad large OO systems can be? :D.

Seriously though I think that people are becoming interested in FP because they see the limitations of their current tools. That's what happened for me anyway.

Also I don't know that Haskell will become mainstream, but something that looks way more like Haskell than Java will.

ML has been around for 40 years, but only lately have algebraic data types been catching on somewhat.
Surely there are reasons. And those reasons need be nothing to do with whether it's worth using Haskell in 2016.
Haskell might be bad, but its unofficial slogan is "Avoid success at all costs" -- so I don't think lack of fire necessary implies it's shitty (which is I think what you were implying.)
Actually, Simon PJ clarified that it's "avoid success-at-all-costs" and not "avoid success at-all-costs".
I've always interpreted it (and I'm not sure Simon would disagree) as a serious "avoid success-at-all-costs" and a tongue-in-cheek "avoid success at-all-costs".
In any case, it's mostly a joke.
How long has ML been around and how long did it take for it to become 'mainstream' enough to be used by big teams at Facebook and Jane Street?
Haskell definitely has problems. I'm a huge fan of the language, but I think its disingenuous to pretend like its flawless.

To name a few:

1. Poor debugging tools. Unfortunately this is sort of intrinsically tied with non-strict evaluation. Typical evaluation stepping debuggers would be sort of unpredictable in haskell. Along these lines, haskell doesn't have stack traces enabled by default, and reading them is sort of tricky.

2. Clumsy exceptions model. There are asynchronous and synchronous exceptions, with the later being further broken down into exceptions in pure code or exceptions thrown in IO. Only exceptions thrown in IO are catchable. You can think of exceptions in pure code as similar to "panic()" calls in other languages, except they're even tricker due to lazy evaluation, and aren't necessarily guaranteed to be triggered due to slipperiness with laziness. Also since exceptions are used for interrupting computations (timeouts, for instance) and there isn't a way (other than some type class conventions) to distinguish between interrupting exceptions that should be allowed to propagate and exceptions due to "exceptional circumstances", catching all exceptions safely is a tricky matter.

3. Record syntax leaves a lot to be desired. It's incredibly easy to run into situations where you would have conflicting functions due to record syntax. Lenses are a partial fix for this, but its sort of annoying that something like row polymorphism isn't just a part of the language.

4. Laziness can make reasoning about time and space complexity trickier. Generally this is a little overstated, but you'll occasionally run into space leaks.

There are definitely real problems with the language, and some of them (such as poor debugging capabilities) can be legitimate showstoppers to use in industry, but generally I find that its advantages far outweigh its negatives.

The bits about exceptions and IO isn't quite right.

So far as I'm aware, there is no technical difference between exceptions thrown in IO versus exceptions thrown in pure code. There are two contextual differences.

First, exceptions can only be caught in IO, but everything running has IO above it somewhere, or it wouldn't be running in the first place.

Regarding exceptions thrown in IO versus elsewhere, it's worth noting that exceptions thrown anywhere are only actually thrown if the thunk representing them is forced. IO values tend to be used quite close to where they are created, whereas an exception in lazy, pure code might hide in the creation of the leaf of a tree or at the end of a list.

Yeah, just reread how I worded this and it's not quite correct. Your points here about how all synchronous exceptions are handled the same is correct. I think what I was trying to get at was that exceptions in pure code are usually treated like fatal errors.

The biggest challenge is definitely how easily exceptions can slip by handling code unless you make strict use of throwIO with synchronous exceptions (or something equivalent like throwM from exceptions). My favorite example is the following:

let foo = try . return $ error "foo".

Which evaluates to "Right * Exception: foo".

Many people learn Haskell (or FP in general) at university and then wash their hands of it and refuse to ever touch it again. Perhaps consider it could be a matter of preference or right-tool-for-the-job rather than the fact that the unwashed peasants just haven't "discovered" enlightenment yet.

Spoken as someone who prefers FP but is not a zealot.

I'd love if you can point out the incorrect points, but I understand that's not your responsibility. Thanks for the feedback!