Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> That's why when choosing between two languages, assuming both are well suited to the job at hand, a company should always pick the one with the wider adoption unless the other is so significantly "better" to trump lesser adoption.

I think it plateaus at a certain point. You don't need the largest community, you just need critical mass so you don't have to build everything yourself. In fact, at some point being the biggest ends up diluting the talent pool because of the number of people getting into it for the money, and this is becoming a much bigger problem as the traditional job economy dries up and the demand for programmers increases.

As to being "significantly better", I think Haskell has that in spades. In fact the things that make Haskell better are probably difficult to appreciate by a lot of younger programmers who are using relatively new languages and frameworks like Node and Rails. When you start seeing the effects of code rot and programmer turnover on a codebase over time, the types of static checks that are a couple orders more powerful and simultaneously less verbose and restrictive than what most people think of when they hear "static language" (ie. Java), then Haskell really starts to shine.

Personally I think companies that invest in Haskell are going to start seeing major dividends in terms of productivity and agility over the lifetime of the company.



I don't disagree with your major point - "companies that invest in [[functional programming languages with a strong typing system]] are going to start seeing major dividends in terms of productivity and agility over the lifetime of the company." Haskell in particular I'm not sure of - the 'code rot' could easily manifest itself in performance. Haskell's laziness makes slow code and code that use up a lot of memory hard to locate, and at times require significant refactoring, to correct, though this is offset by haskell's type system somewhat...

You can see this manifesting in the project of the article's author under the "Not All Sunshine and Rainbows" section.

What I'm getting at - Bad code can be written in any language. IMO what's more important with regards to the language is how easy does it make to fix it.

I've only used haskell for my thesis project as well as having toyed with it in my free time now and then over the past two years, and have no commercial Haskell experience, so perhaps someone with more experience can chime in...

EDIT: A Haskell project I was working on: http://stackoverflow.com/questions/21654081/how-do-i-optimis...


So far as code leaks go I think the professional story is divided. Everyone runs into them, some people learn to fix them, those that do tend to think of them as a little annoying but not significantly more so than profiling and tuning strict code.

Fortunately, outside of space leaks the Haskell runtime is actually really quite fast. At the end of the day most of your code which isn't leaky (buggy) will be really fast almost for free.

But that second step can be painful right now. The tools exist to profile and debug space leaks, but they're not cohesive and require a fair amount of black knowledge. It's also fairly murky as to how to escalate: if you've identified your problem area, strictified it a bunch, and it's still broken... well what then?

The answer seems to be growing that internal expertise. There are enough people out there writing enough stuff that a dedicated student of the runtime can learn all of the tricks needed to really attack failures like that—profiling, unboxing, reading core, figuring out the inliner, and a variety of style guide hints to making things all work smoothly (e.g. avoid the Writer monad).


Speaking as a part time GHC contributor (and alleged "core haskeller"), theres A LOT of exciting work going on right now for improving debuggability wrt correctness bugs and performance tuning.

GHC 7.10 is slated to (hopefully have): 1. exceptions will come with stack traces! a. Some of this same work will also allow for sampling based based performance tools b. mind you, a lots still in flux 2. theres a non zero chance you'll have in langauge facilities to create threads that get killed automatically if they exceed certain programaticaly set CPU/Memory/other resource limits! 3. Other things which are a combination of hard work and clever research grade engineering

I myself (as Tel knows) have plans for making GHC haskell AMAZING for numerical computing, and my wee ways of contributing to GHC are guided by that goal


Upvoted.

"The answer seems to be growing that internal expertise."

Or you can go with OCaml. :)


Sure, or any strict language. There are a lot of benefits to laziness though even before you start to consider other Haskell/OCaml deltas. Laziness provides a much better platform for separation of concerns which has enabled Haskell programs to have an unheard of degree of decomposition and reuse.

As always, it's a tradeoff. At this point, I don't personally feel afraid of debugging core or profiling space leaks. I don't feel like I'm much more than 50% up to date on techniques to fix them... but when they arise I have little trouble eliminating them.

Lazy resource deallocation is a problem of lazy IO. The solution is to not use lazy IO and that's tremendously tenable today due to libraries like pipes and conduit.


I agree.

Would like to note I've spent more time trying to optimize this[1] than writing code, however.

http://stackoverflow.com/questions/21654081/how-do-i-optimis...


On a quick glance I'd suggest (in addition to the responses already given) to (a) use a more efficient structure for holding events (Data.Sequence or maybe Pipes) since (++) has bad performance when the left argument is large (as is definitely your case), (b) for all of your "static" types, add a strictness annotation and possibly an {-# UNBOX #-}, (c) consider replacing System.Random with mwc-random, it's more efficient and has better randomness.

Diving into processOrder since it's the big time/space hog I think strictness annotations might help uniformly since there's a lot of packing/unpacking going on. To really dig in you can add some manual SCC annotations or dump core on it and see what's doing all the indirection.

These are all pretty general, high-level Haskell performance notes, by which I mean if you learn them once you'll be able to apply them much more quickly in the future whenever you find bottlenecks.


Yeah, a good starting point is that if something is running slow, and if there's lists involved, look at how you're using them. Also, as a special case, replace String with (strict or lazy) Text or Bytestring, as appropriate.


Unfortunately OCaml leaves a lot to be desired after working with Haskell for a significant amount of time. As far as I know GHC's extensions makes the type system much more powerful in non trivial ways. For example things like type families, data kinds, kind polymorphism, type level naturals, RankNTypes, and so on. That being said OCaml is still orders of magnitude better than most other options. As well, a least for me, it is a lot more work introduce explicit laziness all over the place into eager language, than it is to go the other way and apply selective strictness.


Is it fair to say OCaml is a more practical choice (as of now)?


That depends on the domain.


Would appreciate it if you would expand on that. (My comment was general in nature.)


Well, most important is probably availability and stability of domain relevant libraries in either language. There are areas Haskell has well covered and areas where it's thinner...

It's also been the case historically that Haskell had much better concurrency support - I'm not sure whether that's still true - in which case a more parallel workload might push Haskell-wards (if it's not so parallel that simply spinning up N entirely separate processes make sense, in which case concurrency support doesn't matter).

I'm not familiar enough with the current state of OCaml, or with Haskell libraries outside the domains I've been playing in, to really give a thorough run-down of specific domains, sadly. I'd be interested to see it if someone else took a swing.


Or F#, if you are using .net or mono. It's pretty well integrated into Visual Studio these days, and quite good in Xamarin Studio.


Sadly, although the performance of mono is good enough for most things i.e. GUI, it's several factors slower in performance-critical applications.

Although I'm excited about F#, the experience in Visual Studio is really great.


> What I'm getting at - Bad code can be written in any language. IMO what's more important with regards to the language is how easy does it make to fix it.

Hm, not sure I agree with this. As a professional rubyist I am aware of the wide variety of bugs that can and do happen because of things that Haskell simply wouldn't allow you to do (at least without pathological abuse of the language that would never pass a code review). The thing that makes Haskell special to me is just how much the commitment to functional purity and a powerful type system buy you in terms of decreasing the surface are of potential problems.

You've rightly pointed out that Haskell has its own memory and performance pitfalls that are very difficult to debug, but my instinct is that those things, while perhaps being showstoppers for embedded and realtime systems, are not intractable in a typical server environment, and that it's orders magnitude easier to improve the tooling around detecting and solving these problems than it is to ever make a language like Ruby code safer and require fewer tests.

Of course I'm an utter beginner at Haskell, so I don't have a real sense of its downsides at scale, so take my opinion with a teaspoon of salt.


I really wish Haskell weren't lazy by default. Laziness is great in places, allows you to write very declaratively, and even allows for some computations that would otherwise be impossible or less efficient. However, most of the time, you envision and write code as a series of steps (even though theoretically in a functional language, you're just writing an expression). In a practical matter, the cases in which lazy evaluation becomes desirable exist, but are limited. Most of the time, you want, and expect when you write it, your code to be evaluated strictly. Of course you can enforce strictness manually with `seq` and bang notations and the like, but this clutters up your code and might not even matter if you're using library code which doesn't do the same. IMO Haskell would greatly served by having laziness be opt-in, not opt-out. But its pretty ingrained at this point, and there doesn't seem to be too much of a push to change it (who knows how much extant code would be broken by such a change).


> However, most of the time, you envision and write code as a series of steps

Perhaps counterintuitively, I disagree here. I think using laziness enough will eventually change your mind that most code must be thought of in such discrete steps. Instead, I tend to keep in mind and think constantly about how a computation might be partially delivered and how it might be consumed. This is part of the declarative promise of laziness playing out, I feel.

Ultimately I don't think there's a "right" decision. I'm comfortable in strict and lazy languages. I do think everyone should experience both strict and lazy evaluations enough to no longer be worried about them and instead just see each as another, separate form of computation. At the very least it'll make you much more aware of what evaluation order and normalization feel like.

(I'd also highly recommend everyone plays with a total language for a while, too. That feel is quite distinct.)

At the end of the day, I feel like having laziness by default and picking around for places which ought to be strict is very dual to having strictness be default and picking around for places to make lazy. Both are pretty annoying.

I do think people are generally more sensitive to problems of excessive laziness than they are to problems of excessive strictness. Manually wiring around stopping criteria and consumption control through all of your (no longer decomposable) loops/recursion is the price of strictness. Both problems are helped by tooling, as well.


It certainly doesn't need to be thought of as a series of discrete steps, and laziness supports that view. Laziness is part of the Haskell philosophy of staying high-level: so high level that you're not even telling the machine in what order to perform its computations. However I stand by my contention that most of the time, when we as programmers write code to be executed, we're envisioning it as a series of steps: this is a major reason why monadic code is so popular and why Haskell's designers invented do-syntax to imitate imperative code. You say that it would be just as annoying to specify the individual places to make lazy, but I struggle to agree with that. After all, the vast majority of programming languages have strictness by default (even other functional languages like SML or Idris) and don't present any difficulty to the programmer. On the other hand, getting around Haskell's default laziness is a constant issue for performance-minded code (from what I've seen; certainly it's a constant topic of conversation), and makes stack traces and debugging hard.


To give a specific example, strictness is a pain in the butt when you try to write a combinator library. I have once tried to write a Parsec clone for Ocaml, and sometimes, I had to write functions in eta-expanded form, lest I enter an infinite recursion.

tel is right. We are desensitized to the problems of strict evaluation. It's the default, so we accept it as a fact of life. Lazy evaluation on the other hand, is "new", so whatever problems it have are magnified by our unwillingness to handle new problems. This is made even worse when we try to use lazy evaluation the same way we use strict evaluation: you get even more problems, and none of the advantages.


I think people are desensitized to the downsides of strict code. I don't think that either is "better", but I appreciate having spent a lot of time working in a lazy-by-default language.

I think the best option is total-by-default, honestly. I really like how Idris works, for instance. If you must work with some code which is non-normalizing then your choice of laziness/strictness can be a major architectural one—like organizing the entire pipeline of your program around a lazy consumer stream/set of coroutines.


Idris, one of the candidates to be "the next Haskell", is strict by default. It's not a mature language (+ecosystem) yet, but certainly usable and interesting. If you like exploring new cool concepts, you should have a look at it! (Plus it's very easy to learn when you know Haskell already.)

http://www.idris-lang.org/


Idris also makes it trivial to annotate laziness, something most languages are lacking, also because it is total by default the evaluation strategy doesn't actually matter for all the total code.


Yeah, Idris really seems like a cool language. I wish it was better documented, at both the usage- and implementation-level. The source code for example is woefully under-commented; a quick grep of the source shows about one line of comments for 15 lines of code.


I think you are generalizing a bit too much. You may very well write code that way, but I don't. Having come to haskell from several years with ocaml, I found the switch to lazy by default to be entirely irrelevant and inconsequential. As long as I have the ability to be strict when I need to, and lazy when I need to (which both languages give me), I don't care which is the default.


In practice, I've found space leaks in Haskell code to be a bit analogous to extraneous copies in C++ code or NullPointerExceptions in Java: They're usually not a huge problem, but sometimes you get it wrong even if you're experienced and know what you're doing.

We've only had one really disasterous space leak and it was caught and reverted right away. The hardest ones are generally the slow ones where the servers take 3-7 days to run out of RAM and fall over. If you never go more than a few hours without a code push, you might not even notice it.


FWIW one reason the service mentioned in the blog was so fast was because of laziness. Because it didn't need most of the request, the work required to parse it was mostly avoided.


>Haskell's laziness makes slow code and code that use up a lot of memory hard to locate, and at times require significant refactoring, to correct

This is largely mythology built up around a misunderstanding of the grain of truth at the core of it. Lazyness can create pathological performance issues, just as strictness can. 90% of the time neither matters, 5% of the time you need strictness, 5% of the time you need laziness. Using strictness in haskell is very simple, and knowing when you need to is very easy to learn. The profiling tools make it incredibly obvious when laziness is causing a problem. And I can't even imagine a case where it requires significant refactoring. It is generally adding a couple of "!"s or importing Module.Strict instead of Module.Lazy.


> This is largely mythology built up around a misunderstanding of the grain of truth at the core of it.

I agree. I've encountered a few space leaks in my Haskell code, but it's always been pretty easy to track down: profile the memory usage and look for a conspicuously huge peak. It will usually be fixable by forcing an intermediate result, or using a different recursion strategy (eg. a fold instead of explicit recursion). Haskell functions tend to be so small and single-purpose that there are no knock-on effects of doing this refactoring.

I think there's a perception that 'Haskell is difficult to debug', whereas the reality is more like 'Haskell will reject all of the easy bugs'. In other words, the average difficulty of a Haskell bug may be higher, but the density is less.


> eg. a fold instead of explicit recursion

Wouldn't adding some bangs in the patterns kind of do the same thing as using foldl'?


Yes. Most recommendations for implementing recursion in Haskell that I've seen have amounted to writing it in terms of folds. You gain the benefit of experts vetting the code, and novices being able to understand what it is doing it a glance.


I'd like to add that for the 90% of the time it doesn't matter, 95% of that time you could use a total language. This is one of the joys of using a total language: seeing what's still easy!


I see no reason why strictness would have pathological performance problems. If you don't need to compute a value, dinner compute it. No performance problems.

I also see no reason you would need laziness for 5% of programming problems. That seems absurd given that the overwhelming majority of programmers have gotten along without it for 50 years.


Most programmers use laziness all over the place, they unfortunately have few tools for introducing it, and thus don't recognize it as such.

For example in C/C++ your only ability to introduce laziness is via manual thunking, if, or the logical conjunctive (&&), and disjunction (||) which have non-strict semantics. For example you often see the idiom of:

    if (x != NULL && x.foo == bar) { ... }
Which relies on (&&) being lazy in its second argument. Lazy languages allow one to write things like && and if without needing them baked in. For example:

    until :: Bool -> a -> a -> a
    until b t f = case (not b)
      True -> t
      False -> f


>I see no reason why strictness would have pathological performance problems. If you don't need to compute a value, dinner compute it. No performance problems.

You just answered your own question. "If you don't need to compute a value, then don't compute it" is laziness.

>That seems absurd given that the overwhelming majority of programmers have gotten along without it for 50 years.

No they haven't. Most programmers don't understand it, but they tend to use it on a regular basis.


> You just answered your own question. "If you don't need to compute a value, then don't compute it" is laziness.

No -- "laziness" is saying "the programmer wants us to compute this value, but we don't need it just yet, so we're going to create a thunk that will sit on the heap until it's evaluated or garbage collected". Strictness is doing what the programmer says, which involves the programmer deciding what does and does not have to be computed while he's writing the program.


Perhaps I was not clear. You stated the very reason for laziness: to not compute things you don't need computed. There are many cases where it is very beneficial to be able to determine this at evaluation time, rather than when writing the code. Hence laziness, and hence it being used all the time in most mainstream languages.


You say it's used all the time -- so how about you give an example of a "lazy" solution to a problem in, say, C?


I implement laziness "manually" all the time in Objective-C.

For example, imagine something happens which invalidates a property which must be calculated (say, a bounding box for a graphical object).

Instead of immediately recomputing it, just set it to nil, and only recompute it the next time the property is actually accessed.

This way you can harmlessly invalidate it multiple times without doing a potentially expensive calculation (which just gets thrown out by subsequent invalidations).


That's not laziness, that's just cache invalidation.


It's fair to say that it's laziness, in my view. That sort of thing is just a manual implementation of what laziness would do in a particular situation. The closure that the thunk would hold is essentially diffused into the object that contains the lazy property.


A fast sorting algorithm in Haskell degrades gracefully to a (faster) selection algorithm when you don't ask for the whole thing.

In other words, "sort lst" gives you a sorted list, but "take 5 (sort lst)" gives you the first five elements, without sorting the rest of the list.


Java example:

    if (logger.isDebugEnabled())
        logger.debug("..." + ...);


SomeObjec *getObject(){ if (!theObject) theObject = createObject();

return theObject; }


foo || bar


Every year I read on HN that this year is Haskell's year. What's so different about 2014? The whole 'only for REAL PROGRAMMERS ' argument still hasn't gotten any traction, my dudes, lisper's been trying it since the beginning of time.

Anyone got a link to a good todo-mvc implementation or something like that?


>Every year I read on HN that this year is Haskell's year

Really? Every year I read on haskell a bunch of uniformed dismissal of haskell from people who seem to have a deep seated hatred of learning. How do you get "this year is haskell's year" from his comment at all?

>Anyone got a link to a good todo-mvc implementation

A what? MVC is an object oriented pattern, I would certainly hope nobody tried to do it in haskell.


Every year, on a Haskell thread, someone calls me a noob for not knowing it. Then you get like the same 3 or 4 dudes talking about how it's only a matter of time until the enterprise picks it up and all the dumb people go away. The some stuff about static analysis, and I'm like, that's it?

I just want to see a working to-do list application, or anything resembling that size.


>Every year, on a Haskell thread, someone calls me a noob for not knowing it.

That sounds a lot like you putting words in other people's mouths. I've never seen anything like that.

>Then you get like the same 3 or 4 dudes talking about how it's only a matter of time until the enterprise picks it up and all the dumb people go away.

Or that.

>I just want to see a working to-do list application, or anything resembling that size before we start the name-calling.

Now I am even more confused. Why do you want to call people names, who do you want to call names, and why do you want to see some random toy app first?


"In fact the things that make Haskell better are probably difficult to appreciate by a lot of younger programmers who are using relatively new languages and frameworks like Node and Rails"

Are you reading this stuff? I'm not going to talk to you if you're just being a dick. I know you can read, so stop being obtuse. Come up with something, quick.


Yes, I am reading it. That does not say anything even remotely close to "ulisesrmzroche is a noob for not knowing haskell". I am not being a dick, I am being polite and trying to understand where you are coming from. I don't see how insulting me helps either of us, only how it makes your claims that "haskell people keep insulting me" rather hypocritical.


Ok, nevermind dude. You're either not being honest or really can't understand nuance in the English language, which, either or, doesn't give us a lot of room for arguing. Saying 'a lot of younger programmers probably don't appreciate the best parts of haskell' is clear Ageism. I think it's annoying.


Since I said that, let me be perfectly clear. It's not ageism, it's experience-ism. There are things that you learn when you work on a code base that is 10, 20, 30 years old. There are things you learn when you've been a programmer for 10, 20, 30 years. A lot of the pain Haskell solves isn't apparent in a lot of Node or Rails apps simply because they are so new. That's it, don't read too much into it.


Omg, that's exactly the same thing but more PC. Whatever, I hate you HN. I'm taking my ball and going home.


Hey don't be the white person complaining about racism or the man complaining about sexism. If young people weren't getting a shot in the tech industry because of discrimination then I'd be a tad more sensitive to your protestations. But as it is, you're irrationally sticking your head in the sand. If you don't think that learn things and come to new insights that take years to develop then there's nothing I can say to convince you. But if you stick with it for a while, come back to me in 10 years and let's do a code review on what you wrote today and then we'll discuss if you still think I'm ageist for saying there are particular lessons learned through experience.


Hey, don't take it too bad. If you say anything negative about certain topics you will get downvotes. It's mostly because people not in love with certain topics have learned to just leave them alone and it's left a big echo chamber where anything positive will be upvoted and anything negative will be downvoted.

You'll notice this by seeing that in non-Haskell threads, critical remarks about Haskell are upvoted, while in 'Haskell threads' such as this one where an echo chamber forms, anything critical about Haskell will be downvoted. It's an interesting behavior, but it says a lot more about certain cliques than it does about HN.

Don't worry about it too much and get on with actually using practical tools to solve real problems and leave the echo chamber in their own peaceful world. Everyone is much better off.


Wow, that's smug. My comment had nothing to do with Haskell. He said I was being ageist when I said there are some things that only become apparent with experience.


Reverse-agism is part of an egalitarian mindset of many HN commenters, who believe experience is more important than individual variation in skill. For them, skill and ability increase with experience, so it is an objective fact that young developers as a group are going to be worse by most measures.

So when someone out of college makes more than someone with 10 years experience, they assume this must be due to agism, since the 10 years experience must, in their view, be more important than being one of the top graduates of that year.

On the original comment, I usually associate Haskell with younger programmers, since it is taught in many schools like MIT and UW. So I found the comment a bit grating since I thought Haskell was the one thing we could have.


"On the original comment, I usually associate Haskell with younger programmers"

Huh. FWIW, I associate it more with older programmers. Certainly, some of the more interesting and visible members of the Bay Area meetup are older than me and I'm not fresh out of school.


What a ponderous false dichotomy. No one believes experience matters more than individual variation in skill. Don't put words in my mouth.


>Saying 'a lot of younger programmers probably don't appreciate the best parts of haskell' is clear age-ism

No it isn't.

>I think it's annoying.

Ok, but that doesn't support the claim you made and I questioned.


As a 21 year old this is not ageism in the slightest, it is reality that as you see more and more problems the applicability of some solutions becomes more apparent. For example, when talking to seasoned engineers who have written a lot of concurrent code they immediately understand the value of purity, and immutable data because they have been burned by the problems that crop up when you try to write threaded programs using shared mutable memory.

On the other hand if you take a 20 year old student still doing their undergraduate degree (like many of the people in the classes I TA), and try to explain the value of immutable data, many of them just don't get it. It has nothing to do with their intelligence or age, but the fact that they haven't written enough code to develop a sense of why such a thing would be useful.

If you want example apps their are plenty littering the internet all covering the various web frameworks, for example here is one covering Happstack: http://happstack.com/docs/crashcourse/index.html


Are you for real? It's like deja-vu. I guess I should know better by now. There's probably some guy in a lisp thread who has been on my end of this argument for the last 20 years or so.

http://en.wikipedia.org/wiki/Ageism#Ageist_prejudice


I know what ageism is. You quoted something that is not an example of it. Given that this is entirely pointless, would you mind if we went back to the actual discussion?


The dude that said just said it was 'experience-ism', do I have to explain what nuance is? You've gotta help me out here, I can't do it all on my own.

All you keep saying is 'no its not'. And then trying to move on as if that's the final word. Not interested in talking to you bro, we're not going to come to any kind of understanding.




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

Search: