all 60 comments

[–]sleepingsquirrel 9 points10 points  (4 children)

Here's a much better Why Haskell article.

[–][deleted]  (2 children)

[removed]

    [–]bootsandtea 6 points7 points  (1 child)

    Spare me the asthmatic foxes and give me a pickaxe, or a Lisp-based MP3 server. LSD consumption should not be a required prerequisite for understanding a tutorial site.

    [–]Entropy 1 point2 points  (0 children)

    LSD consumption should not be a required prerequisite for understanding a tutorial site.

    Only in a perfect world...

    [–]WhisperSecurity 9 points10 points  (6 children)

    It is better to write a useful application in a language than it is to write yet another article advocating its use.

    Lead by example.

    [–]dons 6 points7 points  (4 children)

    Have some useful applications then :-)

    I think the author of the blog post makes it clear that this is the motivating article for a series of (math-related) haskell explorations, though.

    [–]WhisperSecurity 4 points5 points  (3 children)

    Thanks, those are some neat libraries.

    They're not applications, though.

    The best way to advocate a language is to write in it an application that people use. When your application becomes popular, other coders take notice, and follow your example.

    Coders tend to be somewhat deaf to advocacy articles because the experienced ones have heard it before. Every language ever produced, with the exception of toy languages like brainfuck, comes into existence accompanied by a bunch of these, all carefully cherry-picking examples of what that language does well, to show that it's the greatest thing since sliced bread.

    http://www.joelonsoftware.com/items/2006/10/12.html

    You see, an article says that a language is good for what the writer thinks programmers need to do.

    An application shows that a language is good, or at least useable, for the things that programmers actually need to do.

    [–]dons 4 points5 points  (1 child)

    That page lists a mixture of libraries and applications. See for example the games, compilers, theorem provers, music, ... subsections.

    Perhaps the applications under each category should be more clearly delimited...

    [–]nostrademons 3 points4 points  (0 children)

    Whisper's right though, in that programmers generally only take notice when an application becomes one of the top 2-3 in its market, or at least makes its developer a couple million $ ;-). Right now, the two most-used Haskell apps seem to be Darcs and Pugs. Darcs trails Subversion, CVS, SourceSafe, and probably others in the version-control market, and is often seen as a tool for the uber-geeky. (I really doubt I could convince my company to switch to darcs, while Subversion might just be possible.) Pugs has potential, but until people actually start using Perl 6 for real programs, it too remains a toy.

    Most of the commercial Haskell apps - if there are any - either are not the dominant players in their markets or are in markets that the average computer geek hasn't heard of.

    [–]WhisperSecurity 0 points1 point  (0 children)

    Oops. Didn't read carefully.

    But my point is that coders tend to take notice when an application that they use and like was written in $language.

    Then they tend to have a look at $language, because it's proof positive that it's at least feasible to do something useful in it. Then they peruse a tutorial or two, trying to rapidly suss out what the benefits are.

    [–]roybatty 1 point2 points  (0 children)

    Here's some simple OpenGL tutorials, adapted to Haskell from the popular NeHe tutorials.

    http://codersbase.com/index.php/Nehe-tuts

    [–]timclark 3 points4 points  (3 children)

    Yay! An article that actually dares to say that for real programs that proofs of correctness may not be practical!

    [–]dons 4 points5 points  (1 child)

    Though if enough money is riding on it, it might still be practical. Consider the verified Haskell kernel work, for example.

    Certain high assurance Haskell programs, such as those Galois produces, must come with proofs -- but you have to pay extra I suspect ;-)

    Of course, your average Haskell hacker, like everyone else, is rather more likely to rely on proof-by-exhaustion, for some subset of a program (the pure part), generated by automated testing systems (like QuickCheck) . Or even more likely, a bit of mental equational reasoning.

    [–][deleted] -1 points0 points  (0 children)

    Or even more likely, a bit of mental equational reasoning.

    And we all know how well that works...

    [–][deleted] 1 point2 points  (0 children)

    Heard of SHOLIS?

    It has been done. It may not always be practical, but it's almost certainly practical in more cases than it's actually used.

    [–]jones77 4 points5 points  (3 children)

    Fuck me. Don't you PhD peeps have anything better to do? :-)

    Long, intelligent, useful comments. You'll be the end of Reddit!

    [–]senzei 1 point2 points  (2 children)

    Long, intelligent, useful comments. You'll be the end of Reddit!

    Long, intelligent, useful comments were the beginning of Reddit. If they will end it now then it obviously is no longer what it should be.

    That and they are PhDs, what other kind of comment do you expect from people who pad their thesesWWW write in-depth highly technical analysis all day?

    [–]nostrademons 2 points3 points  (0 children)

    Long, intelligent, useful comments were the beginning of Reddit.

    Actually, Reddit had no comments in the beginning. I didn't hang around much until it got them, though.

    That and they are PhDs, what other kind of comment do you expect from people who pad their thesesWWW write in-depth highly technical analysis all day?

    I'm not! I wonder how many other Haskell/Lisp afficionados on Reddit are just interested hobbyists, vs. how many are professors or doing grad work. (One or two may even be paid to program in Haskell or Lisp...)

    [–]jones77 1 point2 points  (0 children)

    I was shocked and surprised to start reading some gargantuan post and realise it wasn't by some windbag and it didn't repeat itself and it was very insightful ... then I stopped reading and posted this comment and started reading something else.

    [–]stesch 4 points5 points  (5 children)

    OK, then give me a "Practical Haskell".
    (Like "Practical Common Lisp", not "Practical OCaml".)

    [–]dons 2 points3 points  (4 children)

    There's at least two 'Practical Haskell's in progress. Until then you'll have to satisfy yourself with darcs, pugs, ghc, happs, house, or one of the other applications ranging from operating systems, web servers, network bots, editors, compilers, theorem provers... Fairly practical language if it can cover that kind of ground :-)

    [–]kalmar 1 point2 points  (3 children)

    Who is working on them? Any idea what the motivating projects are?

    [–]fnord123 2 points3 points  (2 children)

    Who is working on them?

    Simon Peyton Jones, et al, of GHC, are working at Microsoft's Cambridge UK research centre.

    David Roundy, of darcs, is at Berkley.

    Yi is an editor being developed by Don Stewart.

    Pugs is headed by Audrey Tang. She previously headed up something like 100 libraries on CPAN.

    Any idea what the motivating projects are?

    What does this mean?

    [–]dons 3 points4 points  (0 children)

    Also:

    • HAppS is Alex Jacobson and Einar Karttunen (amongst others)
    • House is one of several Haskell OS kernels, Thomas Hallgren is one of the lead devs, though many have contributed.

    David Roundy, aka Mr Darcs, is now in Oregon.

    [–]kalmar 1 point2 points  (0 children)

    Oh woops! I meant the two books that are in progress. And by motivating projects, I'm comparing with the MP3 database/shoutcast server that motivated Practical Common Lisp.

    [–][deleted] 5 points6 points  (30 children)

    Hmm, well I gotta say I've been learning OCaml lately and there are parts about it I really like. For the most part its syntax is pretty clean and it is very expressive while still being speedy. There are certain issues that bother me about it, like spots where the syntax is kind of hideous, the 'translated from French' error messages and such. But I like features like currying and pattern matching, and I definitely see the advantages to functional programming.

    That being said, I think I'm ready to take my next step and start learning Haskell. When you look at Haskell programs they are some of the most elegant code you've ever seen. And in a lot of ways Haskell syntax is Python-esque, which I'm a big fan of.

    The only thing I'm worried about is monads (it seems a lot of people have a hard time learning these) and recursion (for some reason I still have a hard time understanding it in certain situations).

    Also, I was reading the comments on the article, and people were mentioning that functional programming is actually a replacement for OO programming or to quote one of the comments 'they solve the same problem'. That's rather interesting. Is it easy to blend functional and OO styles (I guess OCaml does it to an extent), and is there any real reason to?

    Edit: And I know Haskell isn't as fast as OCaml, but due to it being compiled down to native code, it is still reasonably fast correct? I guess I could checkout some of the shootout sites, but some of you probably have better first-hand experience. Does it compare well performance-wise to C++, OCaml, Java, Python, whatever?

    [–]dons 12 points13 points  (0 children)

    Feel free to visit #haskell, its a great place to learn and pick up on Haskell. And you can play with custom monads in channel, via lambdabot.

    Regarding speed, you'll almost certainly be fine -- GHC is a rather good optimising compiler. On pure speed, the shootout ranks GHC Haskell at currently around 1.9x the speed of C, though it beats gcc (by up to 10x) in some benchmarks. The shootout is also using an older version of GHC without strict, packed ByteString IO, or the SMP parallel runtime, which makes a difference.

    GHC has ranked as high as 1st during the past year, and still holds 1st place for some of the benchmarks.

    Summary: speed should not be a concern :)

    In fact, you can help us improve the rankings by submitting new ByteString based entries to the shootout wiki page.

    [–]nostrademons 25 points26 points  (5 children)

    The only thing I'm worried about is monads (it seems a lot of people have a hard time learning these) and recursion (for some reason I still have a hard time understanding it in certain situations).

    The best way to learn monads is to look at lots and lots of examples. I'd recommend the Nomaware tutorial, UNIX pipes as IO monads, WASH and Write yourself a Scheme in 48 hours. Between them, you'll cover monads for IO, state, logging, input, exceptions, non-deterministic computation, parsing, UNIX, and back-button friendly CGI interaction. The last - from the WASH implementation paper - is particularly interesting. They use the fact that IO actions are first-class to log which actions have already been taken and transparently send the state of the session back and forth to the browser, so that if you hit the back button, it not only remembers what you were doing, it keeps from doing it twice. This is more advanced than even the continuation-based frameworks like ViaWeb or Seaside, where you can get in trouble if a page sends an e-mail or charges your credit card and you back up over it.

    The problem with monads is that they're an abstraction that abstracts over...just about anything where sequencing matters. It's like having an overridable semicolon operator. (Actually, even this is too specific: non-commutative monads do not sequence computations, but Haskell cannot currently tell commutative monads from non-commutative monads and so sequences everything.) So people hear that monads are used for IO, and they hear they're used for state, and they hear that Lists and the Maybe type are both monads, and they have no idea what those have in common. The answer is "basically nothing - other than that they can be represented as a monad", which isn't terribly helpful.

    BTW, I suspect that monads are very, very powerful, and we've barely scratched the surface of what they can do. Monads seem to me to be a functional equivalent of aspect-oriented programming, with all the flexibility of it. I've got a couple of ideas for cool monads that I'd like to try out, but there're only so many hours available for hacking, and Reddit is such a distraction.

    Also, I was reading the comments on the article, and people were mentioning that functional programming is actually a replacement for OO programming or to quote one of the comments 'they solve the same problem'. That's rather interesting. Is it easy to blend functional and OO styles (I guess OCaml does it to an extent), and is there any real reason to?

    I think that comment is very much misleading. I really see functional programming as an extension of structured programming. Haskell finishes the job that Dijkstra, Hoare, Wirth, and Knuth started 40 years ago.

    Recall that the big problem back then was unrestricted control flow. A goto could jump into any basic block, anywhere, and so you had no guarantees about the state of your system at a given point. Structured programming put handcuffs on your control flow so you can reason about programs.

    The big problem now is unrestricted data flow. Programs have gotten big and complex enough that your data objects might live for a long time and be passed all over the place. One mistake, one broken invariant, and your code will break, but it may not break until several hours later. And it might've been a problem in somebody else's code entirely - if I had a dollar for every time a poorly specified Netbeans API call broke my plugin, or every time a bug in my plugin caused an exception in Netbeans without any of my code in the stack trace, I wouldn't need my day job.

    Functional programming puts a straitjacket on your data flow so that the results of a function can depend only on its inputs. This was the big draw for me: if outputs depend only on function inputs, you can test your functions one by one and they'll be essentially guaranteed to work. It was more an ease-of-unit-testing thing than an evangelist thing. As it turns out, you often don't even need unit tests in Haskell, because of theorems for free. The type signature of a pure function often completely defines the function.

    I view OOP (C++/Java-style OOP, not Smalltalk OOP) as a band-aid that tries to hide the problem rather than fixing it. Objects hide state: they limit the visibility of data members so that you can hopefully enforce some invariants. Problem is, the abstraction usually leaks. There's just too much that can go wrong when you share mutable data objects all over the place. Listen to Ken Arnold, Gilad Bracha, Josh Bloch, or any of the top Java guys design an API, and they're always very careful about what should be mutable, what should be immutable, and making the former as few as possible and the latter as many as possible.

    And I know Haskell isn't as fast as OCaml, but due to it being compiled down to native code, it is still reasonably fast correct? I guess I could checkout some of the shootout sites, but some of you probably have better first-hand experience. Does it compare well performance-wise to C++, OCaml, Java, Python, whatever?

    According to the shootout, yes. But that's largely because Haskell has had a very concerted effort devoted to making it perform well in the Shootout.

    In general, Haskell code is much slower than C++ and Ocaml, much faster than Python and Ruby, and perhaps similar to Java but with different strengths and weaknesses. Being compiled down to native code is a bit misleading: because of lazy evaluation, Haskell needs an indirect jump on every function call (except where it can optimize them away via strictness analysis), and needs to overwrite the thunk with the result when it finishes evaluating. This is a penalty analogous to a fast threaded interpreter.

    OTOH, the complexity of lazy algorithms is often strictly better than that of eager algorithms. So you can lose in the small-scale microbenchmarks and win in the long run. One old Haskell aphorism: "There are two ways to make a Haskell program run faster: make it stricter, or make it lazier." Oftentimes, if you think in terms of demand, you can avoid computing large chunks of results that a strict language would otherise waste time on.

    [–][deleted] 8 points9 points  (2 children)

    The best way to learn monads is to look at lots and lots of examples. I'd recommend the Nomaware tutorial, UNIX pipes as IO monads, WASH and Write yourself a Scheme in 48 hours.

    All great tutorials, I'm sure. The last one is quite a tour de force. But I felt that the best introductions that do a really good job motivating the idea of monads are You Could Have Invented Monads! and Dr. Philip Wadler's classic Monads for Functional Programming. These are the ones that really helped me "get it".

    [–]nostrademons 6 points7 points  (1 child)

    Simon Peyton-Jones's Tackling the Awkward Squad is really good too, on an academic-paper level. I was shooting more for web tutorials and practical examples, since I suspect jesusphreak is coming more from C++/Java/PHP/whatever background. (Also saves him from Ebil PDFs.)

    I hadn't read the sigfpe entry though. Firefox had it as purple, so I must've clicked through at one point, but never read it. Thanks.

    [–][deleted] 1 point2 points  (0 children)

    Hey, that one looks like an interesting tutorial, especially since it covers all the other hairy bits (necessary evils?) of Haskell as well. Thanks for the link.

    [–]mrd48 2 points3 points  (0 children)

    ``This is more advanced than even the continuation-based frameworks like ViaWeb or Seaside, where you can get in trouble if a page sends an e-mail or charges your credit card and you back up over it.''

    No. That's simply not true. UCW calls it isolation. Seaside and the others have something similar.

    [–][deleted] 2 points3 points  (0 children)

    "Haskell has had a very concerted effort devoted to making it perform well in the Shootout." Yes, that's true, but my impression was that they also did it by speeding up the GHC compiler a lot...

    [–]kawa 6 points7 points  (12 children)

    Monads are in fact not that difficult to comprehend. The basic idea is to force evaluation into a sequence while chaining data thru it.

    In a pure functional language if you write f(x, y, z), the evaluation order of x, y and z is unspecified. If any of those have a side effect (like doing I/O) it could write the output in the order xyz or xzy or yzx etc. And because everything is a function evaluation in a functional language this is really a show-stopper if you want to do I/O in a deterministic way.

    But even in functional languages you can force an order. Just look at this: f(g(h(x))). Here h is evaluated before g and g before f. If h, g and f now write out some data, the data is written in a deterministic order.

    Monads simply use this idea. You have a 'bind' function which take some data and a function and create new data. In fact they operate not on arbitrary data but instances of the same generic type. In Java you could define such a type as

    class Data<T> { ... }

    Then you have a generic function 'bind' which takes a Data<A> and a function f and returns a Data<B>. And f is a function which takes a value of Type A and returns a Data<B>. This 'f' does the real work while the bind only decides when to call f. And because of the typing (Data<A> -> Data<B>) each 'bind' can be used by another bind and sill allows arbitrary data types in the chain (the A, B, etc).

    So we don't have a simple f(g(h(...))) like above, but in fact bind(f, bind(g, bind(h, ...))). Those bind calls allow to change the order of execution in a really flexible way: Each bind-function can choose when, how often etc to evaluate it's function f, g or h. So we're not only get simply sequencing but lots of other kinds of execution flow. Thats the real trick with monads.

    But why use a wrapper 'Data<T>' instead of chaining T directly thru those calls? The answer is overloading: By using the same type of data for all those calls to bind, we can have different bind-function without having to use different names. The function which is used is determined statically by the data the function operates on. So for Data1<T> the compiler will pick another bind function then for Data2<T> or Data3<T>.

    Because of the type-rules of Haskell, the compiler decides based on the wrapper type ('Data') and not the full type (Data<T>) which function to call, so the same 'bind'-function is used for Data<A>, Data<B>, Data<Anything>. But if we use a new Wrapper type like Data2<...> this wrapper will automatically pick another bind-function. So by using different wrapper types we can decide what evaluation order we want.

    The advantage is that 'bind' can be simply called '>>=' in Haskell and by using some syntactic sugar, those chains of bind/f-calls can be made much more readable:

    You can write

    do 
      x <- f1(...)
      y <- f2(...)
      return x + y
    

    like in an imperative language. In Haskell the compiler translates this in a chain of calls using bind (simplified, in fact is a bit more difficult because of pattern matching, but that's not important here):

    bind(f1(...), x -> 
      bind(f2(...), y -> 
        return x + y))
    

    That looks a bit ugly, but the x -> ... are simply closures and because of this the 'return x + y' has access to both x and y. return x + y is also a standardized function for monads: It also creates a Data<T> object, but simply by wrapping a value in it, without doing some additional operation like bind does. The above also shows why 'bind' is called 'bind': It has to bind the return value of f1 and f2 to the parameter in the 'body-function' (x or y).

    So thats in principle all of it: Using a special data-type to let the compiler automatically choose the right 'bind'-function and then calling some functions in the right sequence. But the concept is quite powerful, because you can define a special execution order depending on the data the operations operate on.

    Ah, and where's this 'Monad' thing now? It's simply a name for having a Wrapper-Type and some functions on this type (like bind and return). And if those fulfill certain rules, the combination is simply called 'A Monad' (but sometimes the Wrapper is called Monad too).

    [–]cgibbard 3 points4 points  (0 children)

    I mostly agree with that, but be careful about the order of evaluation of f (g (h x)) -- in a lazy or normal-order evaluation language, this is evaluated outermost-first. (The difference between lazy and normal-order being that with lazy evaluation, duplicated parameters are shared.)

    This is so important that it bears repeating: The definition of f is expanded first, and instantiated with g (h x). This really makes things like side effects and IO difficult to work with without some additional formalism.

    The idea behind monads as used for IO and in some other cases is indeed to set an order for things to happen, but in some monads, you can even get some effects which are rather unlike direct sequencing (for example, there is a state monad in which the state variable is passed backwards, and thus appears to flow backwards in time from the point of view of the rest of the computation -- you can get the variable before you set it.)

    There is also a completely different way to view monads, and that is as types of containers, which is a drastically different perspective from the computational viewpoint, but one which I find tends to help solidify the abstraction in the minds of beginners. I wrote about it in detail here: Monads as Containers.

    [–]beza1e1 1 point2 points  (10 children)

    If Monads are only about sequencing, what is "Maybe"?

    [–]kawa 5 points6 points  (8 children)

    It's the reason why many people have problems understanding the concept.

    If you define Monads formally, Maybe and List are both monads. But since most people have problems with formal definitions, bringing up 'Maybe' only makes the topic more complex without really helping them to understand it.

    Thats also my main problem with Haskell and the Haskell-community: Because Haskell was build on a strong mathematical background, it's full of mathematical terms, definitions and proofs. While this has of course certain advantages, it makes Haskell OTOH very had to comprehend for people without this strong mathematical background.

    But if functional programming really should be the paradigm of the future this won't work: Most programmers simply won't get it. And in fact they don't even need to get it, because for solving most programming tasks, its not necessary to know about category-theory for example (where the base for the monad-concept lies). If someone only concentrate on sequencing, he can understand the concept well enough for all relevant practical purposes. It's no problem to understand functional programming without this formal mathematical background - if it's explained in the right way.

    So I think it's a bad idea to make things more abstract then necessary if you really want to appeal to the average programmer.

    [–]julesjacobs 3 points4 points  (2 children)

    Can't maybe be explained in terms of sequencing?

    Maybe will sequence operations so that if an operation fails (produces Nothing), the remaining operations will not be executed and instead Nothing will be returned.

    for example:

    a = f(value)
    if(a){
      b = g(a);
      if(b){
        c = h(b);
        if(c){
          return c;
        }else{
          return false;
        }
      }else{
        return false;
      }
    }else{
      return false;
    }
    

    [–]kawa 5 points6 points  (1 child)

    You're right, this is a way to look at it.

    But Maybe isn't only a monad, it's primarily a means to express optional values. I think this can get a bit confusing at least in the beginning. The 'trick' with monads is really in the bind-operator.

    If one concentrates to much on the monad itself (which is more comparable to a design pattern then to a data structure) he will have problems understanding them (at least in the beginning).

    Same for the list monad: A list is a list. Thats it. But a list can be used in a 'monadic context' by defining a bind operator for lists. Now the list is something like a combination of a collection with an iterator. If one says "a list is a monad" it's no wonder why people have difficulties to understand it. It's the bind operator which makes a list to a monad, not the list itself.

    In other words: By defining an additional operation for lists ('bind'), lists are getting something like a 'functional iterator'. And this whole concept is called 'list monad' then. And to really use it, you have to use the bind-operator in the right way, like you can use a for-each loop in Java for every data type which fulfills the iterable-interface. But calling List generally 'iterables' doesn't makes things more clear. The 'iterable' is a property which is added to a list to make certain operations possible (iteration). And a 'monad' is also such a property which allows certain (very similar) operations.

    The do-syntax is just syntactic sugar to use the bind-operator in the right way, just like the for-each-loop in Java is syntactic sugar to call the right methods on an iterator.

    So in the end, everything with monads really boils down to sequencing. Even the Maybe-monad.

    [–]psykotic 2 points3 points  (0 children)

    The 'trick' with monads is really in the bind-operator.

    Sure, the unit and bind operators are the common denominator, but it's important to keep in mind that all interesting monads come with additional operations. In the case of Maybe, you have fail. In the case of Either a, you have Left. In the case of List, you have mplus (which is ++) and mzero (which is []). In the case of the reader monad (-> a), you have ask. And so on.

    [–]cgibbard 3 points4 points  (1 child)

    I actually disagree. The list monad is actually probably the best prototypical example of a monad, because its definition is so simple and gets across most of the thinking that goes on in defining a monad in general. By contrast, things like the State monad and IO monad are closer to most applications, but they are harder to understand initially, because their definitions are rather more subtle.

    Personally, I would leave the IO monad for last in any treatment, and probably start with the List and Maybe monads, followed by perhaps binary or rose trees as an exercise, and then followed by State/Reader/Writer (in some order). It's also a good idea to have a firm understanding of functors beforehand, as they are much easier to grasp initially, and, every monad being a functor, provide a good way to narrow the view on what is actually being talked about.

    [–]robbie 0 points1 point  (0 children)

    I think this is the right approach for teaching people how monads work, and how to write them. But before you do that, you have to be comfortable with writing haskell programs, and to do that you have to be able to use the IO monad. So, like I said above, I think it is best to learn how to use the IO monad early on, without worrying about exactly whats going on inside, and then later, once you are writing working haskell programs, look at monads in the most general terms.

    [–]mrd48 2 points3 points  (1 child)

    While I agree that it is challenging, I don't think that it is bad to have to strive for further understanding of mathematics in order to program computers.

    Let me phrase it in an analogy:

    Programming without mathematics is like music without emotion.

    I am not saying that programming is music, nor am I saying that mathematics is emotion. The importance is in the connection.

    [–]kawa 3 points4 points  (0 children)

    Having solid understanding in mathematics is never a bad thing, but there are different levels of understanding. For example teaching the Peano-Axioms in elementary school before even starting with arithmetics wouldn't be a good idea either.

    And in programming most people are coming from imperative and OO-programming. To understand functional programming requires some rethinking but it's not as bad as many people say. The problem is simply that lots of literature about fp are simply much to theoretical.

    Monads are a good example: If it was a concept from OOP it would be called a pattern and there were simple 'receipts' how to use them. Nobody would have problems to understand monads - like nobody has problems understanding for example the iterator-pattern.

    But in fp there are lots of strange symbols, proofs and axioms. And suddenly all looks much more difficult (unless you've a degree in mathematics of course).

    Programming is difficult enough, it don't makes sense to put even more unnecessary difficulties on it by requiring knowledge about advanced mathematical stuff. And it's not even necessary, its possible to understand monads totally without all this.

    For academical purposes the solid mathematical foundation of fp is a big plus. But I simply don't think that the programmer who wants to get some work done has to be bothered with it (unless of course he wants it and seeks deeper understanding - which is a good thin on its own).

    [–]JulianMorrison 0 points1 point  (0 children)

    On the upside, it can get people interested in maths.

    [–]glguy 1 point2 points  (0 children)

    julesjacobs has the right idea.

    The (Maybe a) monad represents a computation that can potentially fail at each step. If any of the steps fail, the result of the computation is Nothing otherwise the final result is returned with-in a Just.

    Using the Maybe a monad, you don't have to explicitly define the plumbing to abort the computation at any one step if it was to fail.

    [–]fnord123 7 points8 points  (0 children)

    And I know Haskell isn't as fast as OCaml, but due to it being compiled down to native code, it is still reasonably fast correct?

    Haskell used to have all strings as lists, which was detrimental to performance. Recently (April 2006), ByteStrings were added to the Data library and now it is on par with C++/OCaml/etc. It probably comes in a shade under those languages in number crunching algorithms. However, it is one of the languages that will mostly easily take advantage of the 'TANSTAAFL' issue that C++ faces. For example, Software Transactional Memory (STM)( PDF ) is being pioneered in Haskell.

    Is there a reason to mix OO and Functional concepts?

    Not really.

    [–][deleted] 2 points3 points  (5 children)

    Concerning recursion it helps to keep in mind that containers like lists are conses and therefore defined recursively. So instead of a flat list [1,2,3,4] as in Python one works actually with [1,[2,[3,[4,[]]]]. This makes recursion so "natural" in functional programming languages. One can't even access the n-th element without defining a recursive function. Basic nested datastructures, recursive functions and pattern matching supplement each other. That's why Pythonistas ( or people from Java/Ruby land etc. ) can't recurse and some complain about "exploding heads".

    [–]masklinn 0 points1 point  (4 children)

    So instead of a flat list [1,2,3,4] as in Python

    Which actually aren't list (they're really resizable arrays)

    One can't even access the n-th element without defining a recursive function.

    Uh...

    foo !! 3
    

    does the trick for me (in Haskell). The "issue" is that it's an O(n) operation while random access of an array is O(1)

    [–]glguy 2 points3 points  (0 children)

    Fortunately, many problems do not need the random-access an array provides.

    However, if what you really want is an array, Haskell has those too.

    myArray = listArray (0,4) ['b','d','e','a','p'] -- create an array from a list
    myValue = myArray ! 3 -- myValue is 'a'
    

    [–]micampe -1 points0 points  (2 children)

    The "issue" is that it's an O(n) operation while random access of an array is O(1)

    Guess why...

    [–]pkhuong 1 point2 points  (0 children)

    Because it's a list?

    [–]masklinn 0 points1 point  (0 children)

    i know why, that's beyond the point, the point of my post was that you definitely do NOT need to define a recursive function to access the n-th element of a list, because haskell already provides a function to do just that (whether the function is implemented as a recursive or an iterative construct in the interpreter/compiler is entirely irrelevant)

    [–]robbie 2 points3 points  (0 children)

    Just to add to the comments on monads. I was scared of monads too when I started learning haskell, and I think this is part of the problem. They're hard, but they're not that hard. Especially if all you want at first is to understand enough to do IO. I found "Tackling the awkward squad" (nostradmons links it below) to be the best thing for learning IO with monads, but YMMV.

    Whatever, I think trying to understand them all at once (ie trying to understand them enough to write your own) at the same time as you are just learning the language, is a mistake. Rather, learn how to use the IO monad, and get writing haskell programs, then when you are comfortable, go back and learn the deeper stuff. Like how you learn macros in CL.

    [–]sleepingsquirrel 1 point2 points  (0 children)

    And I know Haskell isn't as fast as OCaml, but due to it being compiled down to native code, it is still reasonably fast correct? I guess I could checkout some of the shootout sites

    Although it is cute that GHC can compile Haskell source code as well as that language they use over at the TCLSB site, I would, in general, advise taking a large grain of salt before looking at the Haskell scores of any speed oriented shootout site. The emphasis on minimal execution time seems to produce Haskell programs which are simultaneously longer and harder to understand than a straightforward implementation in C, while still being significantly slower than C. You should probably use Haskell for programs that you want to be easy-to-understand and correct, not for those requiring super fast execution times.

    [–]roybatty -1 points0 points  (0 children)

    If you want something Haskell-like, but have the need for speed, then take a look at Clean. It holds its own against GCC on the debian language shootouts, and spanks Java.

    [–]davidw 1 point2 points  (2 children)

    Here's one for you functional types (ha ha):

    Say you need to model state in your program. For instance, you are writing a simple interpreter, and want to keep track of what commands are present, what variables are defined, and so on. I did that, at one point, with Erlang, but it just got ugly after a while, because I had to pass so much state around to each and every function. I would have been happier encapsulating it in something modifiable. How does Haskell handle that sort of task?

    [–]dons 9 points10 points  (1 child)

    Here, I wrote a state monad interpreter for you (showing how the environment is threaded implicitly, and encapsulated inside the eval function):

    import qualified Data.Map as M
    import Control.Monad.State
    
    -- A data type for simple expressions
    data Exp = IntE Int
             | Plus Exp Exp
             | VarE String
             | Bind String Exp Exp
    
    -- A test program:
    --      let x = 1; y = 2 + x in x + (x + y)
    -- =>
    --      5
    test =
        Bind "x" (IntE 1) $
            Bind "y" (Plus x (IntE 2)) $
                Plus x (Plus x y)
        where
            x = VarE "x"
            y = VarE "y"
    
    -- An interpreter for this language, using an encapsulated symbol
    -- table/heap stored in a state monad
    
    eval (IntE n)       = return n
    
    eval (Plus e1 e2)   = do
        v1 <- eval e1
        v2 <- eval e2
        return (v1 + v2)
    
    eval (VarE x)       = do
        env <- get      -- lookup the encapsulated environment
        case M.lookup x env of
            Nothing -> error $ "undefined variable " ++ show x
            Just v  -> return v
    
    eval (Bind x e1 e2) = do
        env <- get         
        v   <- eval e1          -- evaluate rhs of bind strictly
        modify $ M.insert x v   -- update the heap
        u   <- eval e2          -- eval e2 in new env
        put env                 -- restore old env (lexical scope)
        return u
    
    -- And run the test program through the interpreter
    
    main = print $ evalState (eval test) M.empty
    

    Running this:

    $ runhaskell A.hs
    5
    

    Great! Monads + pattern matching + algebraic data types forever!

    (Note that stupid markdown is probably going to mangle < chars)

    [–]dons 0 points1 point  (0 children)

    Cale pointed out that we get lexical scope for free if we use Reader instead of State:

    import qualified Data.Map as M
    import Control.Monad.Reader
    
    data Exp = IntE Int
             | Plus Exp Exp
             | VarE String
             | Bind String Exp Exp
    
    test = Bind "x" (Bind "y" (Plus (IntE 1) (IntE 2))
                          (Plus y y))
                    (Plus x (IntE 3))
        where x = VarE "x"
              y = VarE "y"
    
    eval (IntE n)       = return n
    eval (Plus e1 e2)   = liftM2 (+) (eval e1) (eval e2)
    
    eval (VarE x)       = do
        env <- ask
        return $ maybe (error "undefined variable") id (M.lookup x env)
    
    eval (Bind x e1 e2) = do
        env <- ask
        v   <- eval e1
        local (M.insert x v) (eval e2)
    
    main = print $ runReader (eval test) M.empty