Hacker News new | past | comments | ask | show | jobs | submit login
Haskell, and Why It Might Be My New Favourite Language (unbui.lt)
83 points by sambeau on May 27, 2014 | hide | past | favorite | 53 comments



TL/DR; a flimsy write-up on why he did not like Go, followed by a good write-up on what's great about Haskell when you just start to use it.

Again this underlines some ideas I have about both Go and Haskell:

* Go is great from a commercial perspective; easy to learn/understand, but nothing ground-breaking.

* Haskell is great from a technical perspective; ground-breaking all over the place, but takes an investment.

I believe the Haskell investment is one that every serious programmer should like to make as it should make your both work easier _and_ more fun.


I'm undoubtedly a Haskell convert (from Erlang / Scheme / Python) with little experience in Go.

The investment is pretty big, yes, but I also believe it is great from a commercial perspective because it really improves the result for End-Goal-Programming (end goal is to serve business needs, not technology for technology's sake):

    1. Time to market for a product
    2. Easy / clean refactoring
    3. Massive scale code base management
    4. Program longevity and maintainability
1) Time to market is extremely important for businesses and products and schedule over-flow is a common problem in software engineering that Haskell really does help solve. Since building production software in Haskell I've become completely frustrated by Python because I spend far more time building in it due to debugging my own undisciplined habits out of the end product. I'm not a very disciplined dynamic type programmer.

It also produces cleaner and less buggy product for the end-user. Which is so important!!! Particularly as a startup.

2) If you need to cleanup some technical debt from taking short-cuts or not accurately pre-planning architecture, Haskell's type system makes it so friggin' easy your eyes will bleed when you try to do the same in a Python / Ruby / Erlang program.

Additionally, it really allows you to respond to the market better too! If you have to pivot your product it's not "Oh shit, now we're going to have to take that duct taped sewage monster and turn it into a duct taped ninja turtle." it's "Hmmm, well, let's think through the new types a little bit and re-shape some of this code, I know the compiler will tell me when I'm being a silly human."

3. Python and Ruby aren't really appropriate for large scale code bases because dynamic typing means you need an equally massive amount of tests to ensure no one else in the org fucks shit up. It makes team based programming on the same codebase far more manageable!!

4. Once I've built my Haskell programs and wrote a few minor property tests with QuickCheck, they usually run forever. I've rarely ever had a case where I would get unexpected crashes (usually from my not understanding Haskell's laziness earlier on in my Haskell career).

Long-term maintainability is massive factor here too; it's so much easier to figure out what the damn thing and all of its constituent pieces do with the type system!!! It's like having an index and a table of contents for a book. Since most programmers forget their own code anyway (comes back to that fallible human thing), having a neat and correct abstract description of your program and its parts is invaluable to a commercial enterprise.

So, in short, I actually think Haskell is the best language a commercial enterprise could choose. All you need too is one really good programmer that can mentor, then train them as you go; the good news with Haskell is even when you write shitty Haskell code (un-idiomatic, mostly in the IO monad, and barring space leaks), it's usually better than even the good Python and Ruby code those people would be writing.


+1, (1) (2) and (3) are very real problems in industrial software development.

I've been reading a lot how Twitter transitioned from an RoR monolith ("monorail") to SOA when they got big enough, it's a rough journey but I suspect many companies have to take it once they evolve from iterative prototyping/experimentation to correctness at scale.

I've also realized writing good, maintainable code can be done in any language, it's just that some languages (e.g. Go) make it much harder to write unmaintainable code for many of the reasons you've cited above. "Debugging my own undisciplined habits" really hit it on the head.


Yeah, if you ever get a chance to build something for production in Haskell / Scala / OCaml you'll realize how little even Go (which is better than Python and Ruby!) does for you.

The funny thing is, I believe (from real-world startup building experience) that Haskell has allowed me to iterate / prototype my products faster than I ever would have with Python and Erlang (my old go-to tools).

Also, with Haskell, there's no late-night and weekend fires to put out :) Which makes me more productive and generally happier.

[EDIT] To whomever is downvoting these legitimate comments, speak up why you think they are inappropriate for this discussion instead of downvoting.


I have just started learning Erlang - picked it over Haskell, it seemed to "click" better with my brain. What made you make the switch? Am I wasting my time?


Not wasting but you'll think you're a functional programmer, hit Haskell, then realize you were barely a functional programmer.

I used to feel as you did, until I started thinking more mathematically; the idea behind composition and clarity. Erlang has amazing properties but Haskell can, honestly, do much of it better and faster and safer.

Erlang has Dialyzer and type annotations and quickcheck. Use it all religiously because your Erlang programs will get big and messy fast.

What made me switch? STM > message passing actors, Haskell's type system is incredible, and the libraries / tools available are also pretty amazing. Programming in a way that encourages me to think mathematically is just so much more natural, personally.

Composition + a strong type system is an incredible experience. If you want more personal war stories we can do it over email?

I've built very large and performant Erlang software in production and very large and performant Haskell software in production for two of my own startups.


> I've become completely frustrated by Python because I spend far more time building in it due to debugging my own undisciplined habits out of the end product. I'm not a very disciplined dynamic type programmer.

You heard it here first, folks: Haskell is the blub of 2020, made to force sloppy workers to produce slightly cleaner output when they couldn't be induced to do it voluntarily.

Making it more like Java than anyone tends to admit, and leaving intact the advantages Python had over Java.


If you're doing the computer's work "voluntarily" then you're doing it wrong.

Plus, I think his whole point went woosh over your head.


> I believe the Haskell investment is one that every serious programmer should like to make as it should make your both work easier _and_ more fun.

As long as you're developing on linux. IME, trying to use haskell libraries on another OS is hell.


Personally I've had very few issues using Haskell libs on OSX and Windows.


Personally I had so many issues using Haskell libs on Windows that I gave up on the language.

I've documented the details of my complaint here: https://news.ycombinator.com/item?id=5615516


I think this comment from that thread tells you all you need to know:

shpider might be giving you another hint about using Haskell:

(from the README):

"occupation" =: "unemployed Haskell programmer"

"location" =: "mother's house"


Sure, but like I said, "Long story short, I tried installing ~10 libraries with Cabal and only one installed smoothly."


Slightly meta, but: has anyone else noticed how much love languages with very strong type disciplines have been getting on HN recently? Scala, Haskell, Clojure, Go, Rust jump out.

Maybe language designers/toolmakers are getting better at bringing the benefits of stronger typing (superior editor support, faster execution times, less need for unit testing) without as much baggage: highly ceremonial code, complex compiler setup/tooling, etc? I suspect editor/compiler-level type inference, where you can do things like "val x = NewVal()" vs. "NewVal x = new NewVal()" might have something to do with it.

As someone who's swung back and forth across this divide, I get the sense that modern static language development is much less of a pain in the ass than it was 10yrs ago.

I'm less interested in static vs. dynamic than I am in why the community seems to be floating in this direction recently, when the past 5-7 years has been all about RoR, Django, and even Perl.


I do not consider Go to have a strong type system. It's static though.

Strong typing allows you to do a lot and it also solves the problem we fallible humans bring to the table. Humans are pretty good at being creative but extremely terrible with details, remembering things, and keeping track of "hairballs".

Strong type systems solve pretty much all of that.

Now, with some of Haskell's newest features (like Type Holes) it's starting to make dynamic languages look more like children's toys because you get all the power and safety of a type system with the same "do what you want, it will (usually) tell you what you're intending to put there".

Dynamic programming came from a need for rapid iteration of a program because that's how humans work, we "start" then iterate till we have a more complex and functioning program. The problem with that model though, is that the burden of correctness is on us in the end.

Programming in Python is like leaving your dishes pile up in the sink for a week, then spending two hours doing dishes on Sunday.

Programming in Haskell is like taking your dish to your cleaning robot that will wash it, dry it, and put it away for you. All you have to do is know what you want to use the plate for and return to where the robot can get it.


> Programming in Haskell is like taking your dish to your cleaning robot that will wash it, dry it, and put it away for you. All you have to do is know what you want to use the plate for and return to where the robot can get it.

With the occasional smash coming from the kitchen when you find out the robot has been trying to hold all of your plates at once instead of putting them away because you haven't gone to get one out of the cupboard yet ;)


A stack of type t things blowing up because of lazyness... How appropriate ; )


It's now "typed holes", which really is a much better description anyway.


Programming in dynamic types is not easier because you can jump around the type system more dextrously. Programming in dynamic types is easier because you (mostly) can forget that types even exist. That leads to lesser cognitive load, and that always makes a thinking job easier.

That of course makes it more dangerous too, but it's a trade-off.


Even in a dynamically typed language you can't just ignore the types. You still have to make assumptions about what methods and functions can operate on a value; the compiler just doesn't know what assumptions you are making.


I get the feeling that many programmers have been bitten by weak typing too many times and have come to appreciate the benefits of stronger typing.

If you want to apply defensive programming, which is always a good idea, you usually encounter this pattern: "I'm expecting an Int. Is this an Int? No, this is a string. But if I converted it, would the result be an Int? No? OK, then we have a problem, what should I do about it?". Some languages even have automatic type coercion, in which the final result depends entirely on what the language decides, and varies across languages. It's a mess.

Languages like Haskell or the ML family, with their type systems and type inferences, simply won't compile if you say you are expecting an Int and some other part of the program sends anything else. Maybe it's more work for the programmer upfront, but it reduces future headaches, and it's not difficult once you get the hang of it. Many times you don't even have to state the types explicitly, the compiler just knows. Thanks Hindley-Millner!


Static typing != Strong typing. Once you've grokked Haskell it's hard to consider mere static type systems to be type systems at all. Languages like Java, Go, etc. may as well just be dynamically typed for all their type systems do for you vs Haskell's.

I think that revelation may be one of the things driving this new interest in type systems and comparisons of them. Haskell has really opened some eyes and people are wondering how others compare, and are on the lookout for new languages like Rust doing interesting things with strong typing.


Dynamic typing without the metaprogramming, plus tacked-on parametric typing in the form of templates or generics or whatever they call it. Or better yet: no parametric typing whatsoever and no way of making strongly-typed abstract data structures. Or duck typing, which is exactly that.

Yup, no strong typing anywhere.


Plenty of killer bugs are smashed in compile time by the most simple compiler checks.


The weirdest thing with the new breed of strongly typed language, in my opinion, is that they naturally accept sum types, which are completely alien from an OOP point of view. I mean, the magnificiently useful case switch feature you have in most of those new languages translates very awkwardly in, say, Java by using a isinstanceof then some kind of cast, which I gather is Considered Harmful because it breaks encapsulation and type safety, yet case switches are a natural consequence of sum types, and are completely safe, in the context of a type system that have sum types.

Switching on "type" also happens to be a thing I see a lot in what one would traditionally consider bad code, for example, treating a scalar and an array differently in PHP, or having functions that can deal with many different shapes and kinds of JSON blobs in JavaScript. There also have been a lot of hype around the idea of eliminating null references by using Maybe types, which in the end are just a degenerate case of a sum type.

My pet theory is that the ability to keep doing this in a safe and formalized manner is what makes the new breed of statically typed PLs so cool.


In the 90's Java/C/C++ land, one needed to implement lists and dicts and such by hand. Then came dynamic Perl/Python/Ruby where all these handy data types like list comprehensions, map, foreach were part of the language. I guess we mistook easy operations on a rich set of default data types as a property of dynamic languages?

Now we have Scala, Haskell, OCaml, Rust that have all these handy tools by default, but also strong typing, and type inference on top of that.

(Well OCaml and Haskell we had already some time ago, but they were not popular then.)


You could assume it is something inherent, or you could just connect the dots and realize that it's the silver-bullet fad of the decade, just like OOP and various other things before that.


Silver-bullet fads tend to have a grain of truth that gets carried on into the next fad. Loops are still with us (structured programming), we still write polymorphic code (OOP), we still like less verbose type systems (dynamic languages), etc.


No, it's just a second take at removing the "ceremony":

v. 1: let's remove the ceremony along with strong static typing advantages and just hack-fix everything with unit tests.

v. 2: let's remove just the ceremony.


Haskell syntax just seems pretty crazy. I know nothing about it, but I just read it and wish that maybe one could use a few more lines and get better understandability at the expense of terseness.


It's the difference between Eclipse and Emacs. Haskell actually encourages "internalization" of abstractions through terser syntax.

Emacs is like that, you internalize the editor which makes you 5x more productive than you are with an editor that externalizes the abstraction requiring your brain to use another layer of translation (the visual one).

If you learn Haskell, you'll find it quite enjoyable (I do now). The way I think in that language is so much more abstract and precise than it ever was in Python / Scheme / Erlang / Ruby / Javascript.

[EDIT] To whomever is downvoting these legitimate comments, speak up why you think they are inappropriate for this discussion instead of downvoting.


Your enthusiasm has convinced me to give Haskell another shot, do you have a favorite resource I should try? I didn't have great luck prior.


These should get you started:

Really well presented series of lectures:

http://www.seas.upenn.edu/~cis194/lectures.html

Cheat sheet:

http://blog.codeslower.com/static/CheatSheet.pdf

Books:

http://learnyouahaskell.com/chapters

http://book.realworldhaskell.org/read/

"What I Wish I Knew When Learning Haskell":

http://dev.stephendiehl.com/hask/

Haskell Tutorial for C Programmers (useful for anyone coming from an imperative world):

http://www.haskell.org/haskellwiki/Haskell_Tutorial_for_C_Pr...

Hoogle (API search engine):

http://www.haskell.org/hoogle/


Oh I forgot the Erik Meijer lectures are awesome:

http://channel9.msdn.com/Series/C9-Lectures-Erik-Meijer-Func...


One thing you get from his lectures that aren't in other resources is how he views OOP and FP as two different sides of the same coin.

Fascinating to hear how the same ideas are expressed both ways.


Someone told me this: with Haskell you end up reading a lot more up-front than you do "playing around" up-front. The reason for this is the type system which can feel like a straight jacket at first unless you understand it well.

Don't read the monad tutorials. At all. Get a feel for the language with http://learnyouahaskell.com/chapters (you don't need to read the whole thing through, but probably should).

Once you've played with the basics then you should absolutely read the http://www.haskell.org/haskellwiki/Typeclassopedia which gives you a very thoroughly walking through of the Type System and is essential but heavy reading to be at all productive with Haskell.

After that make sure you are using Hoogle to search for functions that already exist!!! http://www.haskell.org/hoogle/

One strategy no one really told me about: search for functions based on their type and less their "name".

Then after that, Gabriel Gonzalez writes some really great noob-intermediate friendly tutorials on Haskell in-general: http://www.haskellforall.com/ (don't start with his stuff though as you should have familiarity with Haskell basics first!!).

Once you're proficient, having Hoogle built into your command-line, using CTAGS + codex, Lambdabot + Emacs, and GHC-mod + emacs is pretty crucial to my workflow.

Hoogle in the commandline is really powerful, CTAGS + codex is basically CTAGS for haskell source files (if you don't know what ctags are look it up), and lambdabot is a powerful tool that is tough to explain but it's the omnipotent haskell bot sitting in the #haskell IRC channel (but you can install it on your machine and query it from Emacs).


> The reason for this is the type system which can feel like a straight jacket at first unless you understand it well.

This is a biggy. It'll feel like the type-system has a personal vendetta against you when you first start. Especially if you come from a language that allows you to coerce types. Basically stop thinking you can get around the type system and instead follow them. See them as connectors of computations rather than carriers of values.


I have really been enjoying the tutorials and online IDE at http://fpcomplete.com


I'll second FPComplete - a lot of people seem to glom really well onto their web-based IDE.


Try this list of resources for beginners: https://github.com/bitemyapp/learnhaskell


Some of that is just unfamiliarity, doubtless. Optimizing code to be read by people unfamiliar with the language is probably not a good habit. I recall once wading into a C++ code base and coming across the line:

    using namespace std; // using namespace standard

On the flip side, people certainly do go overboard with cramming things into a single line (an affliction not at all unique to Haskell) and in particular overuse of "point free" style where it's inappropriate can lead to particularly unreadable code for those not well versed in the particular tricks used to make the code point free (and that's an affliction more unique to Haskell). I don't see either problem in the code in the article, though.


Indeed. But I am not sure if "crazy" is the right word. Perhaps a better one would be "dense". It is not unlike reading a mathematical proof - one paragraph might need an one semester course to be explained.

This is perfectly nice:

firstBatch = take 10 myDoubles

This is not that nice: sieve (p:ps) xs = h ++ sieve ps [x | x <- t, rem x p /=0] where (h,~(_:t)) = span(< p*p) xs

But that's because there's just too many things going on. A comparable Java code would likely span a page.

I guess, for a trained eye, it is way easier to understand what's going on given those two lines, then a full page program, which would likely hide bugs in side effects.


I think such sieve examples do not do languages a favour: It is slow and it's not true, that the Java code is that long. However I agree that it's nicer in Haskell, but the naive variant as given here (and often in fibonacci examples) is very slow compared to the naive version in a standard imperative language. My take: http://pastebin.com/JGnSPEaH. That is 19 vs 37 lines.


Every language that differs from the structure you're familiar with will seem crazy until you learn how to read it. Be that Haskell, Erlang or Japanese it's no different.


This will solve that problem for you:

http://learnyouahaskell.com/

One of the best intro programming books around, just happens to be about Haskell. Miran has a knack for explaining complex technical concepts.

Haskell's structure is actually incredibly readable - significant whitespace enforces uniformity across all codebases, and syntactically separating function type signatures from function declarations is far more readable than, say, Scala where it's all crammed together in one line.

You do have to learn all the operators though, but again, Miran's book is really good for that.


getMultiples is even shorter and clearer written like this:

    getMultiples = [x | x <- [1..999], x `mod` 3 == 0 || x `mod` 5 == 0]


Golf:

  getMultiples = [3,6..999] `union` [5,10..999]


That doesn't sort the output neatly. You need a merge

http://hackage.haskell.org/package/MissingH-0.18.6/docs/Data...


one thing about Haskell: It is different from other languages, but once you got the "mindset" it turns out to be surprisingly _easy_* to use.

* especially, the haskell way of type-abstraction is sound and makes for really nice and convenient libraries in a way that one cannot imagine if not experiencing it form oneself.


As crazy as it sounds, I can confirm that Go is a gateway drug for Haskell.


Go was the gateway drug to Haskell for me too. As soon as I found out the type system wasn't giving me as many guarantees as I thought while making me type annotations I figured I should find a language with a stronger type system. As a bonus, said language had type inference ;)


Have you looked at Rust?


Not yet. It looks like a moving target for now so I'm waiting for a stable release.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: