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

GHC will warn about partial functions/inexhaustive patterns if you compile with -Wall (or even just -fwarn-incomplete-patterns, but -Wall is recommended). I've often wondered if it would be feasible to eliminate the partial functions from the Prelude and turn partiality into an outright error (not that this would ever happen, as it would break a lot of code).

Regarding other code smells that the compiler can't catch: one thing I have come to really appreciate about the design of Haskell is that in the vast majority of cases, the path of least resistance is also the path of greatest clarity, correctness, etc. I mean, sure, you can write your entire program in IO, but it would be supremely irritating to do so. It's just simpler and easier to do it the "right" way, via composition of small, independent, pure functions.

When using other languages (for me, this usually means Java, Python, or JavaScript), I feel like I am constantly having to remind myself not to be lazy and to do things the way that I know to be right. Don't catch an overly broad class of exceptions. Don't rely on shared mutable state when an extra function argument will suffice. Avoid using null pointers to represent failure. Be sure not to use type-coercive comparison operators. And so on. These languages give you so many ropes with which to hang yourself, and even the standard libraries make idiomatic usage of them. Programming defensively feels like working completely against the grain.

Haskell, with its strong immutability and airtight type system, has shown me that it is possible for a language to guide programmers safely through the minefield without placing a severe additional burden of vigilance on their shoulders. It would be interesting to see a more conventional, imperative style language that followed similar principles. Or perhaps the "everything is in the IO monad all the time" nature of imperative code is just fundamentally at odds with code correctness, and we'll always have to fight against it.



I have a 25 kloc Haskell program, and by around 10 kloc I was sure I did't want to need to track down another backtrace-less crash with "head: empty list".

So, I wrote this module: http://source.git-annex.branchable.com/?p=source.git;a=blob;...

It's imported into every module in my program via a common include which also pulls in other support stuff. Now if I slip up and use head, I get a compile time error as there are two conflicting heads. If I really want to (after all, sometimes you have an invariant) I can use Prelude.head, and I can `git grep Prelude\.` to find all the partial code in my program (currently about 15 occurrences). Or I can read the fine comments in my module for a hint to a non-partial version to use.

There are other approaches, but I've found this to be a fine compromise.


> Or perhaps the "everything is in the IO monad all the time" nature of imperative code is just fundamentally at odds with code correctness, and we'll always have to fight against it.

In some languages, like D, you can fight against that, by declaring functions to be pure. That's a bit like having everything in IO by default, but marking the exceptions.




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

Search: