Hacker Newsnew | past | comments | ask | show | jobs | submit | iamdev's commentslogin

They're showing how often coders accidentally write ":wq" in their code, which is a common command in vim (save and quit).


Unless your ideal customer is a tech-entrepreneur, this is all very misleading. It's going to amount to very little lasting growth.


As someone who has been curious about Haskell, I'm happy to hear someone else say this. The way this article was written feels exactly like the "ruby fever" of 5 years ago.


"ruby fever" of 5 years ago

The difference is that Haskell is a very principled language. All of the claims and excitement are actually backed up by mathematical proofs. Pure functions really do make your code easier to maintain.

And no, it's not the case that Haskell is the only language which allows you to write pure functions. People who try to claim that are being silly and dishonest. Haskell's advantage is that its type system allows you to know at a glance whether or not a function is pure.


While I fully agree that pure code is far easier to maintain than impure code, and the advantages of Haskell are numerous, I think it is a bit strong to state that such claims are backed up by mathematical proofs. Ease of maintenance is a fundamentally subjective claim that cannot be proven, but must be borne out by individual experience (as it has been for you, me, and many others).


Ease of maintenance is a fundamentally subjective claim that cannot be proven, but must be borne out by individual experience (as it has been for you, me, and many others).

I disagree. You can make objective measurements of maintainability. You can look at cyclomatic complexity and reusability (both wins for pure functions). You can test how often changes lead to bugs and how often the errors are caught. There are many instances of Haskell code where there is only one sensible implementation of a function, given its type. Hell, some Haskell libraries have even been formally verified though admittedly that is done with external packages.

I will agree on one thing, though: you do run into trouble when you throw around the word all (or indeed any absolute) without actually meaning it.


> You can look at cyclomatic complexity and reusability (both wins for pure functions).

Yes, those are both wins for pure functions. But even there you need an asterisk, because side effects do have their place - the fact of the matter is, the primary task of most real-world software can be summed up as "manipulating mutable state". In light of that I don't think you can necessarily jump from the observation that there are many situations where pure functions are easier to work with than impure ones to the conclusion that pure functions are inherently more maintainable.

But even if that were granted for the sake of argument, it's not much of a win for Haskell. The ability to create pure functions is a feature of every language that has been invented during the lifetime of probably every person reading this post, and therefore not really a differentiating feature of Haskell.

Nor is lack of ability to create impure functions a feature that can be claimed of Haskell, because that simply isn't true. Haskell's real differentiator in that department is just that you've got to jump through hoops to do it. And if your business rules are inherently impure, then it's not clear to me how a language that tries to ghettoize impurity makes them easier to implement.


The win for Haskell is that it wears its statefulness on its sleeve. Of course you can, with sufficient discipline, write pure code in any language, though it can be frustratingly difficult in languages where libraries make idiomatic use of mutation. And yes, you can also write impure code in Haskell, at least for some definitions of "impure".

What you can't do in Haskell is write impure code that claims to be pure (up to the customarily and idiomatically avoided `unsafePerformIO`), or write code whose degree of statefulness is ambiguous. Reliable, explicit, and statically enforced purity holds more than just theoretical benefits. I don't have to read through library code to see if it is thread-safe. I don't have to worry about whether passing a data structure to a library function will result in that structure being mutated behind my back. I don't have to trust code comments that may not be in sync with the current state of the code. Simply by virtue of the fact that a function does not mention `IO` in its type, I can have total confidence that it won't violate my assumptions about its behavior. And I don't even have to take it on faith that the author wrote the correct type for his code; if he hadn't, the compiler would have rejected it. This is the difference between "pure by convention" and "provably pure".

Every language must necessarily have an "IO monad" and interact with the inherently stateful world, or else it is useless. Haskell is different not because you can choose to avoid I/O, but because when you do so, the type system will back you up with perfect accuracy.


But even if that were granted for the sake of argument, it's not much of a win for Haskell. The ability to create pure functions is a feature of every language that has been invented during the lifetime of probably every person reading this post, and therefore not really a differentiating feature of Haskell.

I already dealt with this three posts above:

And no, it's not the case that Haskell is the only language which allows you to write pure functions. People who try to claim that are being silly and dishonest. Haskell's advantage is that its type system allows you to know at a glance whether or not a function is pure.

Nor is lack of ability to create impure functions a feature that can be claimed of Haskell, because that simply isn't true. Haskell's real differentiator in that department is just that you've got to jump through hoops to do it. And if your business rules are inherently impure, then it's not clear to me how a language that tries to ghettoize impurity makes them easier to implement.

That's only the case for beginners who don't understand monads and their associated libraries. For an experienced programmer, Haskell offers much more powerful and expressive (not to mention safe) means of combining effectful computations than typical imperative languages.


It is not a "strong" statement to say that some Haskell code is backed by proofs. There is Wadler's Theorems for free![1] which allows one to reason about pure function's behavior purely from type signatures. As well GHC supports various features that enables one to encode some dependent typing[2] constructs.

Allowing the type of value to to depend on the value itself. A common example being a list that can expresses whether it is empty or not in its type. These types allow one to write functions with signatures like: `safeHead :: SafeList a NonEmpty -> a`. Uses of this function will fail to compile if I can not prove that my list will always be non-empty.

Combine this with the well known Curry-Howard Correspondence [3] which shows that types have a direct correspondence to proofs. The logical extension of this is computer theorem proving languages like Coq, Agda, Epigram, Idris.

For example Coq[4] uses a dependently typed lambda calculus as its proof term language, and sees wide spread use in the formal verification of software. It is not a stretch to say that less powerful types systems like Haskell's allow us to encode some forms of proof. If you view the type checker as an proof checker, one provides propositions to it (in the form of types) and then supplies proof (in the form of terms). These can be trivial propositions like `a :: Int`, which in Haskell there are 2^31 correct answers.

[1] (http://ttic.uchicago.edu/~dreyer/course/papers/wadler.pdf)

[2] (http://en.wikipedia.org/wiki/Dependent_type)

[3] (http://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspond...)

[4] (http://en.wikipedia.org/wiki/Curry%E2%80%93Howard_correspond...)


I'm aware of dependent types and, more generally, the strong undercurrent of emphasis on provable correctness in the Haskell community at large. I don't disagree at all with what you wrote, but it's not what I was referring to with my comment.

My disagreement was specifically with the implied claim that it can be mathematically proven that Haskell code is easier to maintain than code written in other languages. That has indeed been my experience with Haskell, but I do not think it is directly provable. What seems easy for me may be stupefyingly difficult or confusing for someone else.

"How easy something is" is not really a quantifiable measurement; it is a subjective experience. As chongli points out, however, there are related measurements that can be taken, such as cyclomatic complexity, and those at least seem to be correlated with ease of maintenance. So perhaps I'm just being overly pedantic!


I misread your comment, usually people challenge that point. I totally agree that it is difficult to talk about maintainability in an objective fashion, but there is something to be said about having as many of your assumptions in your codebase vs. your test suite. My experiences working in a Ruby code base is that many assumptions have been encoded in the tests, and not notated in the main code base. When those assumptions change there is a large burden on the programmer of having to unify ad-hoc assumptions from both the test cases and main code base. Validating whether those assumptions still hold, or if it is a test from 3 years ago, and has only been vacuously passing.

I found working in a big Ruby code base that this required spending a non trivial amount of time unifying the two. In that regard by minimizing the amount of test code one has to write and maintain I would argue that maintainability goes up. I've also seen a lot of FP practitioners boasting about relatively low test to code ratios, while in the Ruby world often times you have at least 2x test code, since often times you even have to validate assumptions like `object.responds_to? :foo`.


If by mathematical proofs you mean a dense, tangled run-time written in C that is statically linked into every executable then I think I understand where you're coming from.


Or all the other fevers we've suffered through. Haskell seems like an attractive language but I wish boosters wouldn't advocate their languages as the fix to the problems of large-scale software engineering issues when there's little or no evidence for their claims.


There was a cool talk on "The Haskell Chat" episode two [1] that goes over how haskell is used in a large team, some members with expert haskell knowledge, some as just technical end-users of the libraries.

I found it really interesting to see how a large team can deal with a real haskell project.

[1]: http://www.haskellcast.com/episode/002-don-stewart-on-real-w...


Well, the problem with this is that the evidence is locked up in company trade secrets. A lot of the big commercial users of Haskell are in finance and all their code is under lock and key.


The example provided is too contrived. By that logic, here's a way to "match" haskell with php:

$a = range(2,100,2); $b = array_slice($a, 5);


Yeah, I don't touch Java very often (and my Java is more sledgehammer than scalpel at the best of times), but off the top of my head I'd reduce the example to:

int[] arr = new int[50]; for(int x =2; x <= 100; x = x+2){arr[(x/2)-1] = x;} int[] arr2 = Arrays.copyOfRange(arr,5,arr.length);

There's probably a more fluent method to achieve the same result (in Scala, F# and C#, certainly there are), but I'd like to see a considerably less-contrived example from a more-disinterested party.


Haskell's version is type safe. PHP, not so much.


Thanks for pointing that out. The author didn't emphasize that point, and it makes sense now.

Is it me, or was it a bad example for where Haskell "really shines"? I don't like the "use Haskell cause it has these really cool functions" approach. Feels so superficial.


It's not just you.

Haskell is worth the effort, but I don't think the article's author did a great job of articulating why.

Some things I've noticed:

Haskell does not automatically admit an extra "null" value to every type, so you can ordinarily ignore NullPointerExceptions and the like. When you do need a nullable bit of data, you have to do some extra work: You must rename the type from "Foo" to "Maybe Foo" and change all the callsites. These callsites must test for null and specify what happens. (there exists a non-terminating explode() function if you really want it) The build will fail until every last case is covered. This is great for reliability.

Most data in Haskell is immutable. This encourages good programming practice, sure, but it really pays off when you start writing parallel code. Parallel Haskell is by far the easiest way I know to write fast concurrent stuff. On that note, Haskell's concurrency primitives are very well-designed.

Haskell's solution to callback hell is more general and powerful than anything I know. The "do" block is really just super elegant syntax sugar for a CPS chain.

Our unit test suite does not intermittently fail. We restrict side effects such that our build will fail if a test tries to do non-faked I/O. It took a bit of effort to build, but normal use is effortless.


It wasn't so much a bad example so much as it was a trivial one. Perhaps a more powerful one (that displays the advantages of lazy evaluation and higher-order functions) would be the function to generate an infinite list of Fibonacci numbers.

    fibs :: [Integer]
    fibs = 0 : 1 : zipWith (+) fibs (tail fibs)
Even still, it's difficult to get the feel of actually using the language from one function taken from a freshman year CS class.


How about demonstrating the power of laziness by generating the power set of a set? (Taken from Learn You a Haskell).

  powerset :: [a] -> [[a]]  
  powerset xs = filterM (\x -> [True, False]) xs  

  ghci> powerset [1,2,3]  
  [[1,2,3],[1,2],[1,3],[1],[2,3],[2],[3],[]]
Edit: I read LYaH some time ago but this example stuck with me because it's both wonderful and mind-blowing.


Here's a recursive definition which is less cool but less 'magic'

    powerset        :: [a] -> [[a]]
    powerset     [] =  [[]]
    powerset (x:xs) =  yss ++ map (x:) yss
                       where yss = powerset xs

    > powerset [1,2,3]
 
    [[],[3],[2],[2,3],[1],[1,3],[1,2],[1,2,3]]


I think the strongest argument for Haskell is what you can make it not do, not what you can make it do.

Having strong and concise type guarantees is great. Haskell's a great example of that. So is Ocaml.


You're right, it wasn't a particularly compelling example of Haskell's strengths.


Also Scala (just because):

  val a = 4 to 100 by 2
  val b = a drop 5


One thing experiments like this often seem to forget is that our bodies have evolved to eat. Even something as simple as your stomach physically expanding to hold large quantities of less nutrient-dense whole foods has been shown to have an effect on the body and brain.


My company also experienced not getting as much traffic to my site as facebook claimed.

What I was told before I pulled my campaigns is that Facebook considers it a click when the visitor clicks your ad, but BEFORE the visitor is shown a "warning" screen that they're about to leave facebook. not sure if this has changed since. I haven't come back.


I'm sure all the genius's are excited about Apple giving permission to the WORLD to make them work off-the-clock ;)


TLDR: (Using Phil Libin's own logic against him) Startups are likely to fail, so it's just as absurd to say you're doing it to change the world as it is to believe you're doing it for the money. You're still better off joining an organization that has momentum and resources.

This invites inevitable argument though, since: 1. It's endlessly debatable which companies are actually changing the world. 2. The ones most people think of first are based on charity, which is again arguable and limited to very short term gain.


1. Yes.

2. I don't think of the ones based on charity. The ones that come to mind are Google, Facebook, Twitter, Apple, and AOL (in its day).

My point was just that there are other ways to change the world. I used a poor and overdone example by work seemingly related to charity (how come no one is picking on the marine biology example), but you could very well have a world changing impact and be an author or a professor or a painter. Heck, you could be a mechanic or a stay-at-home mom. There's no reason changing the world has to be tied to profession at all.


I should have been more clear that I personally thought your article was spot on. I was only trying to summarize the debate brewing on HN.

Great blog post and really thought provoking.


Thanks! As were your comments!

I admittedly glossed over these issues in the post, but I didn't want to dwell on them because I thought it might detract from the overall message. I kind of did that anyways though.

I like HN because the quality of responses is so much higher than elsewhere, and because you have a forum for fleshing out the glaring issues left in the article. I might delve into the topics you mentioned a bit in future posts. One thing that I think drives people crazy is the whole "change the world" rhetoric in general. It might be useful to explore what that actually means.


Econ 101? Sounds like we need to remember Business 101.

Yes, it's revenue not earnings (profit), but a) as a manufacturer, Apple earns more profit on a sale than Best Buy, which b) makes how much more money they're earning all the more impressive relative to a retailer like Best Buy.


Thanks so much!


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

Search: