8 ms·
Why Haskell is Kinda Cool
- warmfuzzykitten 15y agoGood illustration of why unreadable text colors are kinda lame.
- bcl 15y agoPerfectly readable here. Although not knowing Haskell some of the syntax is a bit difficult to grok.
- ionfish 15y agoHaskell syntax is actually pretty straightforward, once you know what you're looking at. It's difficult at first blush because of the weird infix operator symbols ($, ., <> etc.) but once you get used to them there's nothing too scary. That being said, why not post any problems you have here? I'm sure plenty of people would be happy to help explain Haskell's syntax, and no doubt more people than just you would benefit from that.
- nplusone 15y agoParent is possibly referring to the blog's horrendous color scheme, not Haskell as a language.
- ch0wn 15y agoYou convinced me to give it a try. I'd still be interested in an opposite view. Are there any non-ranty articles about the problems of the language?
- yoklov 15y agoThe downside of Haskell is that performing mutations is more difficult than with traditional imperative or object oriented languages, as monads take some time to get used to. That said, it's a wonderfully elegant and expressive language, and I suggest you just jump in and try it as opposed to looking for someone to convince you not to ;p. Learn you a Haskell for Great Good, and Real World Haskell are both available online, and are great resources. (written from a phone, otherwise I would provide links, though a google search should bring them up quickly) Good Luck! moving from imperative/oo to functional style can be a mind bender, but don't let yourself get discouraged, it's still just code. :)
- andolanra 15y agoA sibling comment mentioned that mutation is difficult; another prominent problem is that reasoning about time and space efficiency in Haskell is rather unintuitive. It's easy to learn a little bit about optimizing functional programs (e.g. through CPS-transforming your functions and taking advantage of tail-call optimizations), and then find your Haskell program even more slow and space-wasteful because it creates a huge number of thunks. (A "thunk" in this context is a zero-argument function whose sole purpose is to be evaluated later; in Haskell's case, to be evaluated when it's "needed" à la call-by-need.) On the other hand, laziness also means you can write apparently inefficient code that nevertheless performs incredibly well, e.g. constructing infinite data structures. There are also both major and minor squabbles of various levels of importance (e.g. Haskell got :: and : mixed up, you can't have two records with the same field name, Bob Harper argues that laziness itself is a mistake, various people would prefer abstractions other than monads for dealing with state) but I think Haskell's performance and Haskell's initial impedance with imperative programming are the big problems—at least, those are the big problems I hear people complaining about. (Then again, I'm an enthusiastic Haskell person, so you probably should find someone who likes the language less to give you a better opinion.)
- Peaker 15y agoI like Haskell a lot, and here's my list of problems with it: http://www.reddit.com/r/haskell/comments/hezgk/haskell_singularity_approaching/c1uwd75 http://www.reddit.com/r/haskell/comments/hezgk/haskell_singu...
- eru 15y agoSee https://bloggablea.wordpress.com/2007/04/24/haskell-records-considered-grungy/ https://bloggablea.wordpress.com/2007/04/24/haskell-records-... Otherwise: If you want to see some articles that also talk about the problems of the language, your best bet is to read the papers of the people who make the language. They are acutely aware of the problems. The downside is, that you have to learn the jargon first. I find most academic papers about Haskell and functional programming surprisingly readable though.
- ionfish 15y agoThere are a few missteps in this article. To begin with, the author claims that a variable of type Double is "a function with no arguments". This is not the case [1]; not everything in Haskell is a function. A Double is just that: an instance of the numeric type Double. They also say that "[T]he Ord "typeclass" ... implements comparisons." But of course the typeclass itself doesn't implement comparisons. A typeclass defines an interface which its instances implement. Consider the Eq typeclass: class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool So to make a type an instances of Eq, we need to implement (==) and (/=) functions with the type signatures provided by the class. It's pretty obvious how this should go for the Bool type, so let's define that and make it an instance of Eq. data Bool = True | False instance Eq Bool where True == True = True False == False = True _ == _ = False a /= b = not (a == b) This is all covered very well by Learn You a Haskell [2]. [1]: http://conal.net/blog/posts/everything-is-a-function-in-haskell http://conal.net/blog/posts/everything-is-a-function-in-hask... [2]: http://learnyouahaskell.com/making-our-own-types-and-typeclasses http://learnyouahaskell.com/making-our-own-types-and-typecla...
- Deestan 15y ago> the author claims that a variable of type Double is "a function with no arguments". I believe he was trying to make the very important point that in a functional language, there is no conceptual difference between a variable containing X of type T and a function with no arguments that returns X of type T.
- ionfish 15y agoHe was, and I was trying to make the point that he was wrong. :)
- lmkg 15y agoIf you were to act like doubles are (optimized) thunks, would that ever trip you up? Haskell's strictness means that its abstractions don't leak as much. If I'm able to pretend that everything is a function, and doing so won't lead me astray, I don't see the point of caring that some things are really values (for some definition of real). That seems like the sort of detail that Haskell makes a point of protecting you from.
- aklein 15y agoI'm thoroughly convinced Haskell is the String Theory of programming. You may not be convinced by it, but you sure as hell have to be smart to grok it.
- ionfish 15y agoArguments of this kind are both wrong and dangerous. Becoming a good Haskell programmer isn't easy, but then neither is becoming a good programmer simpliciter. The language itself is conceptually novel compared to imperative languages, but the concepts themselves are neither difficult nor abstruse. Actually I find Haskell refreshingly simple; it's a lot like Lisp that way. I'm sure you'll agree that it's unfortunate that so many people are put off by a subject's alleged difficulty, rather than encouraged by it. However, given that this is in fact the case, wouldn't it be better if we concentrated on saying how enjoyable, intellectually stimulating and useful learning certain things was rather than discouraging people from even having a go?
- baltcode 15y agoI liked Haskell when I tried it for all of these reasons. However, there were a few problems I had: 1. Debugging logic. I LOVE its typesystem, which catches most of my errors. However, sometimes I have algorithmic/logic errors. In a perfect world, I would have worked those out well before coding. But once I have coded it, I just don't know how to debug my code. I have gotten so used to gdb/pdb as my last resort that I am lost without it. Does anybody have any idea debugging Haskell programs? 2. Its Lazy evaluation sometimes get in the way of tail recursion optimization unless you force it, and can lead to the stack getting full. But this can be handled by forcing evaluation with seq.
- Peaker 15y ago1. There's the ghci debugger, though I don't know if it is practical (I don't use it myself). Alternatively, you can use Debug.Trace (or the http://hackage.haskell.org/packages/archive/TraceUtils/0.1.0.1/doc/html/Debug-TraceUtils.html http://hackage.haskell.org/packages/archive/TraceUtils/0.1.0... extension), which makes "print-based" debugging easier than in imperative languages: Say you have: processValue f = after . map f . before If you want "print-based" debugging, you can use Trace.Utils.traceAround: processValue f = traceAround "processValue" $ after . map f . before Or, if you just want the results of "after": processValue f = traceId "Result of after: " . after . map f . before Alternatively, there's also the FileLocation package, which gives you filenames + line numbers in your debug prints via Template Haskell macros. 2. Controlling evaluation is indeed tricky. Haskell programmers take manipulation of infinite data structures (of any kind) for granted -- but then if they want to control stack use, it gets a bit tricky. Other languages take stack use management for granted, but if you want to have infinite arbitrary data structures, it gets tricky. I personally prefer Haskell's choice, because it means that having infinite structures doesn't contaminate the code with effects (which explicit suspensions/resumptions of computations would do), but it could probably be done better (e.g: move laziness/strictness annotations mostly to the type-level).
- eru 15y agoHaskell doesn't even really have a stack. It's more like a spaghetti stack.
- alnayyir 15y ago>most classes of bugs are caught at compile time This is false, can we stop pretending that hindley-milner solved the Halting Problem?
- T_S_ 15y agoThink of it this way. More compile time errors = fewer run-time errors. You can still have bugs of course. Most my Haskell run-time bugs are because I defined a partial function. Many standard functions are partial too. I find that changing a working Haskell program to add new features is easier than other languages I have used. You pay a price (understanding your problem better) up front to get there, but the dev cycle is very fast after that.
- davidhollander 15y ago>More compile time errors = fewer run-time errors. But any possibility of 1 run time error means you'll still need to manually write a test asserting the correct runtime behavior anyway. So the typical argument is that typed languages don't actually save you any work, and might actually increase the likelihood of errors by discouraging unit testing. I'm not claiming this holds for Haskell, as my experience with the language is not great enough to pass any judgement yet.
- T_S_ 15y agoOk. Fewer run time errors = fewer tests. Also check out QuickCheck for automatically generating tests. It's very handy.
- Peaker 15y ago1 test is not enough to cover the functionality of various functions. In Haskell, types are enough to prove some properties about functions, so you don't need to write any test for the proven part. For example, you can write a RedBlack/AVL tree implementation in Haskell where the types prove that the tree is balanced. Haskell's type system is not strong enough to prove the order invariants are correct, though, so you'll still need to test that, but that's easier. In a language with a weaker type system, you'd end up with more test code (for balance tests) and less guarantees (tests give no assurance). Also, many bugs slip through tests that are meant to cover these classes of bugs. You don't get any guarantee from tests. Types give you nice guarantees. They're not as comprehensive as very-expensive tests, but they're pretty cheap. You get far more reliability-bang-for-the-buck from types, and thus the baseline from which you start testing is much higher.
- pnathan 15y agoHere's a question for the Haskellers out there: How does Haskell help you write less code? What mechanisms are in the language that allow you to write higher level abstractions (as compared to, say, Ruby or Python)? How does Haskell help you to express concepts that are very difficult to express in other languages?
- BasDirks 15y agoBecause it's pure, you can know what comes out at the other end when you put something in. (That sounds more disturbing than it's meant to be). You can build pieces that you can reuse within many different structures, like different types of pipelines and filters. All without having to worry about leaks or the wrong stuff ending up in the wrong place.
- andolanra 15y agoHaskell abstracts things at an even higher level than most programming languages. For example, the infamous monads are a way of abstracting out the details of how 'effectful' computations (i.e. computations that do something other than simply taking arguments and returning values) should work. Monads model effects like exceptions, mutable state, input/output, nondeterminism, and so forth, and by abstracting them into the same pattern, it allows you to write functions that work with any effect in the same way. For example, if I have a list of operations which have effects and all have the same result type, I can sequence them together using the sequence function, so for IO: sequence [putStrLn "foo", putStrLn "bar", putStrLn "baz"] will print those three strings on their own lines. However, I can use the same function for Haskell's equivalent of null: sequence [Just 3, Just 8, Just 5] -- results in Just [3, 8, 5] sequence [Just 3, Nothing, Just 5] -- results in Nothing, because Nothing is -- propagated if it occurs or for nondeterminism sequence [[1, 2], [3, 4], [5, 6]] -- results in every possible list whose first -- element is drawn from the first list, whose -- second element is drawn from the second -- list, and whose third element is drawn from -- the third list. or for any other effect that Haskell has. A lot of learning Haskell has to do with looking at the abstractions Haskell offers (monads are only one; you also get things like arrows, functors, applicative functors, &c) and understand how you can phrase your problems in terms of them and consequently use Haskell's abstractly written functions to your favor. A great practical example here is parsing; parser combinators can be expressed as monads or as applicative functors, both of which make your parsing code very small and quite natural to read. For example, the following is a function to parse strings like "(552,864)" using the Parsec parser combinator library: parseDigit = oneOf ['0'..'9'] parseInt = many parseDigit parsePairOfInts = do string "(" p1 <- parseInt string "," p2 <- parseInt string ")" return (p1, p2)
- leif 15y agoDoes anyone know how to turn off the extra mouse cursors? That is bugging the hell out of me and I can't concentrate on the article enough to read it (but I really want to).
- domhofmann 15y agoScroll to the bottom of the page and click the power icon on the enflock widget.
- mortice 15y agoWhich still leaves mouse pointer images all over the document. Horrendous.
- badhairday 15y agoType javascript:$('.ms-mouse').hide(); into the address bar and hit enter after you turn off Enflock.
- leif 15y agothis is the dumbest thing in the world
- deleted 15y ago[deleted]
- bonaldi 15y agoHow awful is enflock? (NB: Very)
- johanbev 15y agoIndeed. I refuse to read this. Haskell is probably awesome, but this site is clearly not. Time to get noscript running again...
- davidhollander 15y ago> Since most of my bugs in other languages stem from unwanted interactions between pieces of code via side effects, this is kind of a big deal. Is this really the case for most people? Most of my errors are syntax, pattern matching, not considering certain cases, unrefined logic, etc. Creating external side effects such as writing to files or sockets is not that big of deal or as error prone, because after you learn that trick once, it behaves in the same way. The POSIX standard does not change as frequently as my own code :)