10 ms·
For a language that prioritizes "safety" above all things, there is an awful lot of flying blind and dangerously in Haskell. It's so, so easy to write Haskell c
by jes5199 13y ago
For a language that prioritizes "safety" above all things, there is an awful lot of flying blind and dangerously in Haskell. It's so, so easy to write Haskell code that's safe until you change something distant in the system, which changes when things get lazily-evaluated, and now you have a very serious resource leak. And because of the IO restrictions, you aren't likely to put logging in your code - and if you do, the logs will themselves change the lazy evaluation behavior of your code. I've seen Haskell programs that stop crashing when you pass in --debug !
If the Haskell environment was more like a virtual machine - like in Java - where you could connect into a side-channel and see what types of data were persisting in memory as the program ran - you'd at least have a chance of debugging this sort of thing. But instead it compiles to machine binaries.
There doesn't seem to be any interest in the Haskell community in making tools to deal with this sort of thing - they say "you should learn not to make resource-leaking code". Which is the same thing the Lisp hackers say - "just learn not to make type errors".
- lukeqsee 13y agoI concur when it comes to lazy-evaluation. I once lost 10% of my grade in a project because I removed a debugging print statement, which in turn made a data-structure lazily evaluated, which in turn meant that a significant portion of my type-checking was never evaluated.
- dietrichepp 13y agoWhat? This means that you must have been using exceptions to communicate type-checking information. That's just a terrible way to write Haskell. Exceptions only have nice semantics when they're e.g. thrown in the IO monad. -- No, no, no, no! checkValid :: Int -> () checkValid x = if x >= 5 then error "Invalid number!" else () -- This works fine. checkValid :: Int -> Either String () checkValid x = if x >= 5 then fail "Invalid number!" else return () This may sound a bit harsh, but I think you deserved to lose that 10% if you had such a fundamental misunderstanding of "lazy evaluation".
- cliftonk 13y agoTelling a kid in college (I was a sophomore when I was writing Haskell) that he deserves to lose 10% over something like that is crazy. The obvious to us, many years into programming professionally, is not always obvious to newer folks.
- tensor 13y agoThe ideal purpose of grades is teaching. It's a way of informing you of the parts of the curriculum that you do not yet fully understand. This sounds like an entirely appropriate situation to lose grade points on. Unfortunately, grades now also serve as some poor measure of intelligence or competency in many people's minds.
- ubercow13 13y agoA grade is also how they decide if you get your undergraduate degree. It would be a strange shame if that decision had nothing to do with your intelligence or competency as you imply.
- Jtsummers 13y agoMarking work is a way of teaching, grades are used as a measure of understanding. I had a friend in college that, at the start of a semester, was typically a mediocre to borderline failing student if you looked at the marks on his assignments. By the end of the semester his understanding would be on par with mine (typically As in CS/math courses with the occasional B). However, his grade reflected his poor early start with the material and he'd end up with Cs. Now, that's good enough to pass to the next class, but it still helped to screw him over when he started applying to jobs after college.
- learc83 13y agoI think that depends on the project. If the project was the entire grade, then yes that's a bit much. But if we're talking about 1 of 10 assignments, then 10% really isn't that much. I've had plenty of assignments were the granularity was just something like excellent, good, pass, fail.
- tibbe 13y agoYou can connect to the run-time system e.g. using the ekg package.
- hibikir 13y agoAnd that's why the 'war' has just moved to the JVM: Closure is a Lisp, Scala steals a whole lot of things for Haskell, trying to make it actually practical. I think Haskell's ultimate role is a bit like Ruby's: It can't really win, but it's destined to be influential. That's a much harder road for Lisp, as its greatest strengths are also its greatest flaws.
- thirsteh 13y ago> Scala steals a whole lot of things for Haskell, trying to make it actually practical. LINQ is "practical Haskell," so is most of Rust (if "practical" means approachable to imperative programmers.) Besides being on the JVM (which is a big plus), Scala hardly makes anything more practical than it is in Haskell. In fact, Scala programmers tend to migrate to Haskell (and ML languages) rather than the other way around.
- platz 13y agoIf by LINQ you mean the map/filter/fold crew, I think this may be selling Haskell a little short. You could say the same about python. At least F#'s computation expressions give you the full power to create your own monads with it's "computation expressions", and in LINQ things are more statically locked down.
- thirsteh 13y agoRight -- I wasn't sure whether F# would be considered "practical" in this case.
- platz 13y agoI guess F# isn't practical if you're building a WPF application (I agree the tooling is lacking). Otherwise it seems like it can do everything C# does (including mutation, classes, interfaces, properties), only with a slightly unfamiliar (at first) syntax.
- cordite 13y ago
- thirsteh 13y agoIf you take a little care to e.g. make data types' fields strict, this tends to be a non-problem. It is harder to debug the code since it is lazily evaluated (and it's not imperative!), but recent versions of GHC provide pretty powerful profiling, stack traces, etc. I'm not sure that I would agree that you're flying "blind or dangerously" either way--at least not when it comes to building up large unevaluated thunks. I would agree somewhat if you were referring to code using unsafePerformIO, which makes it the programmer's responsibility not to break referential transparency. While that doesn't tend to be an issue either, Safe Haskell does mostly solve it.
- jes5199 13y agoI disagree. I've never seen a program fail because of an unsafePerformIO call, but I've never seen a Haskell project that didn't suffer from at least one mysterious, hard-to-solve unevaluated-thunks-filling-up-RAM bug. Even the company that was on HN recently cites thunk leaks as their biggest problem with Haskell: http://engineering.imvu.com/2014/03/24/what-its-like-to-use-haskell/ http://engineering.imvu.com/2014/03/24/what-its-like-to-use-...
- implicit 13y agoHi. I wrote that article. I've never seen a Java application that hasn't succumbed to an unexpected NullPointerException at least once over its entire development cycle. That doesn't mean that the language isn't a reasonable choice. It's just a common problem that you have to accept on that platform. Space leaks in Haskell are similar. You're going to run into them every so often, and you'd really rather not, but they're easy enough to deal with.
- virtualwhys 13y agoI'd take a NullPointerException over a memory (edit: space) leak any day of the week; the former is instantly resolved, the latter, ?. Anyway, in Java 8 they've started taking steps to address the null problem with the new Optional type, and, FWIW, in Scala nulls are a more or less a non-issue when you use the FP side of the language.
- agumonkey 13y ago"I've seen Haskell programs that stop crashing when you pass in --debug !" Haskell has a self correcting compiler.
- judk 13y agoIt is true that Haskell is about denotational safety (correctness) not operational safety (performance limits). You do not need IO limitations for logging. You can use Debug.Trace Haskell does have a heap analyzer. Like C, you can choose to compiler an instrumented binary with debug symbols. There are a huge suite of tools coming around this year. Debugging and analysis has been a huge theme recently. Simon Marlow's recent book gives a taste, as does the latest Communities And Activities Report.
- tene 13y agoThe book mentioned seems to be "Parallel And Concurrent Programming In Haskell", available online here: http://chimera.labs.oreilly.com/books/1230000000929 http://chimera.labs.oreilly.com/books/1230000000929
- pekk 13y agoHow is a program correct if resource leaks cause it not to perform the intended task?
- axman6 13y agoI think this is more of an implementation issue than a language issue. A haskell compiler could choose to reevaluate everything every time it's demanded, and it would run in very little space. GHC uses thunks to represent computations which haven't been run yet, which are replaced once any threads evaluates them. This can lead to space leaks, but I don't believe there's any requirement that this be how the results are evaluated. GHC chooses this evaluation strtategy because it usually results in faster code, but obviously can lead to problems if you don't know what you're doing. Like all languages, it takes experience to avoid whatever deficiency exists in your language of choice; it won't be obvious to a beginner why the naive implementation of fibonacci works for some values but overflows the stack on others, but they will eventually learn.
- chongli 13y agoHaskell the language is concerned with proving small theorems about the program as specified by the source code. Actually running it is outside the scope of language specification; it's an implementation detail. GHC (the defacto compiler for Haskell) makes a lot of resource tradeoffs to try and achieve better performance.
- massysett 13y ago"There doesn't seem to be any interest in the Haskell community in making tools to deal with this sort of thing" Actually there's a great deal of interest in dealing with lazy evaluation and making it more explicit so that you're less likely to leak resources. http://hackage.haskell.org/package/pipes http://hackage.haskell.org/package/pipes
- rbanffy 13y ago> they say "you should learn not to make resource-leaking code". Which is the same thing the Lisp hackers say - "just learn not to make type errors". <sarcasm> We should just stop writing the bugs. If, instead, we focused in writing code that runs correctly, everything would be much better. </sarcasm>
- mcv 13y ago> they say "you should learn not to make resource-leaking code". Which is the same thing the Lisp hackers say - "just learn not to make type errors". Errors are unavoidable, no matter what language you use. The important thing is that you can catch them in testing. I don't value static typing very highly because type errors show up quickly. Pass the wrong type, and execution fails. Ideally this happens in your unit tests. During development. Because you're doing TDD. Resource leaks, on the other hand, are usually very hard to catch, and often don't show up until production.