Slashdot Mirror


Haskell 2010 Announced

paltemalte writes "Simon Marlow has posted an announcement of Haskell 2010, a new revision of the Haskell purely functional programming language. Good news for everyone interested in SMP and concurrency programming."

173 comments

  1. Is it just me ? by ls671 · · Score: 3, Insightful

    I admit that a function with no side effects can ease making things thread safe, but are recursive style functional programming languages really used that much in "SMP and concurrency programming" nowadays. I wrote some code in that category but I never envisioned a functional programming language would suit the job. Am I the only one ? ;-))

    Thanks for your replies,

    --
    Everything I write is lies, read between the lines.
    1. Re:Is it just me ? by Anonymous Coward · · Score: 0

      No, you're not the only one, but the vast majority of those people just don't know and have never written anything serious in a functional language. Playing at the REPL doesn't count, you have to write a real program like darcs or yi or xmonad or something.

      I spend my days writing interactive GUI apps in haskell, some concurrent, some not, and it's a joy. Writing with locks and heavyweight threads and mutating objects everywhere sounds like a nightmare to me. Except things which are mostly library glue, I can't think of many jobs haskell doesn't suit.

      Except compiling quickly. ghc is not so great there...

    2. Re:Is it just me ? by rjh · · Score: 4, Insightful

      Functional languages are enjoying an enormous renaissance in the field of multithread, multicore and/or multiprocessor environments.

      There are a few really major obstacles to doing multi-* well. The major theoretical one is Amdahl's Law, which puts some extreme limits on how much multi-* can help you. The major practical one is our current obsession with side-effect languages. We need major theoretical advancements to get past Amdahl's Law (if, in fact, it can be gotten past at all). Functional programming is a great way to get past side-effect-based programming, though.

      In a proper functional language, there is no such thing as iteration. There can't be. The instant you say, "each time through the loop, increment the counter, and as soon as it hits this certain value stop," you have stopped programming in a functional style.

      As an example of some really cool concurrent languages that emphasize recursion and functional programming, look at Clojure, Scala, Erlang and F#. All of these languages provide iteration and other side effect techniques if you really need them -- but all of these languages emphasize recursion.

    3. Re:Is it just me ? by lorenlal · · Score: 1

      I guess not, since that's what these folks put together.

      Seriously though, it's my experience that there aren't too many people out there writing much with concurrency and SMP in mind to start with. I'm not sure how they did it, but if they can bring parallelism to another method of programming, then fine by me. The more people get used to utilizing the multiple cores available to them, the better IMHO.

    4. Re:Is it just me ? by arevos · · Score: 3, Informative

      I'm not sure what you mean by "recursive style", but the biggest commercial users of functional programming languages tend to be companies behind high-traffic websites that need to handle a lot of concurrent requests. Facebook developed their real-time chat application in Erlang, for instance, and Twitter uses Scala to handle its message queue.

    5. Re:Is it just me ? by oldhack · · Score: 1

      "Writing with locks and heavyweight threads and mutating objects everywhere sounds like a nightmare to me."

      Past the simplest trivial scenario, it is a nightmare. But asynchronous message-passing scheme works reasonably well.

      I don't know of any widely used multi-threaded GUI kit.

      --
      Fuck systemd. Fuck Redhat. Fuck Soylent, too. Wait, scratch the last one.
    6. Re:Is it just me ? by Anonymous Coward · · Score: 0

      Except neither Scala nor Erlang are functional languages ....

    7. Re:Is it just me ? by ls671 · · Score: 3, Informative

      > I'm not sure what you mean by "recursive style",

      Look at Quicksort in Haskell :

      qsort [] = []
      qsort (x:xs) = qsort (filter (= x) xs)

      This is what I mean, no loops, recursion. I used Prolog and ML to solve logic problems and it is pretty handy. Prolog is especially suited for solving logic problems ( "logic programming" ).

      --
      Everything I write is lies, read between the lines.
    8. Re:Is it just me ? by Anonymous Coward · · Score: 0

      How are they not?

    9. Re:Is it just me ? by ls671 · · Score: 1

      Hehe /. screwed the Haskell code, look here for the source :

      http://www.haskell.org/haskellwiki/Introduction#Quicksort_in_Haskell ;-)))

      --
      Everything I write is lies, read between the lines.
    10. Re:Is it just me ? by arevos · · Score: 1

      > I'm not sure what you mean by "recursive style",

      Look at Quicksort in Haskell :

      qsort [] = []
      qsort (x:xs) = qsort (filter (= x) xs)

      This is what I mean, no loops, recursion.

      Well, all functional programming languages use recursion, so "recursive style functional programming languages" is a bit redundant :)

    11. Re:Is it just me ? by DragonWriter · · Score: 1

      I admit that a function with no side effects can ease making things thread safe, but are recursive style functional programming languages really used that much in "SMP and concurrency programming" nowadays.

      If by "recursive style functional programming languages" you mean (more or less) functional programming languages that support tail call optimization so that tail calls, including self-recursive calls, are efficient, then the answer is "yes".

      Besides Haskell, Erlang, for instance, is such a language , and concurrent applications are one of its main strengths.

    12. Re:Is it just me ? by j1m+5n0w · · Score: 3, Informative

      That's not true unless you are using a different definition of "functional" than I am. I can't comment on Scala since I haven't used it, but Erlang is indeed a functional language. It is not a _pure_ functional language, as Erlang does have some mechanisms for manipulating mutable, global state and message passing, but it's at least as functional as a lot of other language that are widely regarded as "functional programming languages" such as Lisp and ML.

    13. Re:Is it just me ? by harry666t · · Score: 2, Insightful

      Except that
      1. Slashdot thought you're writing HTML and ate half of your code
      2. Put it into a module and load in ghci, then try something like "qsort [1..10000]". Watch the slowness.
      3. The efficient implementation in Haskell uses iteration and is 100 times less readable than equivalent code in C.

      I really like Haskell, but this is not the best example of its strenghts.

    14. Re:Is it just me ? by DragonWriter · · Score: 4, Interesting

      Well, all functional programming languages use recursion

      Most procedural programming languages use (or at least support) recursion, too. The difference is that (1) pure functional language cannot express certain algorithms with iteration instead of recursion because of the lack of mutable state, and (2) languages that don't support tail call optimization (at least in the trivial case of self-recursive tail calls) generally also don't efficiently support recursion, since recursion results in the accumulation of stack frames. A consequence of #1 and #2 is that pure functional languages almost without exception, as well as many less purely functional languages that designed to support programming in a functional style (e.g., Scheme), feature tail call optimization and have tail-recursive constructs as the most idiomatic way of expressing certain algorithms, whereas languages that aren't functional or designed with functional-style programming in mind, often have an iterative approach as the most idiomatic -- and most efficient -- expression of the same algorithms.

    15. Re:Is it just me ? by EMG+at+MU · · Score: 5, Informative

      Amdahl's law is not like Moore's "law". Amdahl's law is an observation of mathematics. You can't ever get around the fact that if you increase the performance of 90% of the instructions in a program, you still have to deal with the other 10%. Even if you increase the performance of 90% of the instructions by 100x or something large, if the other 10% take a long time (like disk access) its going to kill your performance.

    16. Re:Is it just me ? by ls671 · · Score: 1

      Almost all programming languages support recursion so recursion is recursively redundant ! ;-))

      --
      Everything I write is lies, read between the lines.
    17. Re:Is it just me ? by Anonymous Coward · · Score: 0

      Renaissance implies a certain significance or magnitude. There is no need to call it enormous too.

    18. Re:Is it just me ? by DragonWriter · · Score: 4, Informative

      Except neither Scala nor Erlang are functional languages ....

      Erlang and Scala are both languages designed to support programming in a functional style, and both are "recursive style" languages in that they optimize tail calls generally (Erlang) or at least in the most important case of self-recursive calls (Scala) and thus make tail-recursive (or, in Erlang's case, more general tail calling with unlimited depth) programming styles efficient.

      Neither is a pure functional programming language, true.

    19. Re:Is it just me ? by j1m+5n0w · · Score: 1

      I wrote some code in that category but I never envisioned a functional programming language would suit the job. Am I the only one ? ;-))

      Whether it works or not depends on what your task is and how you try to solve it. There are several ways to do concurrency in Haskell, and they're each appropriate in different instances. If you're just calling a lot of pure functions, then "par" and "seq" might be what you need. If you need shared, mutable state, then STM might be a good approach. If you want to do message passing or traditional locking, then using Chan and/or Mvar in the IO monad might be the right thing.

      I'd recommend looking at Real World Haskell chapters 24 and 28.

    20. Re:Is it just me ? by Hurricane78 · · Score: 3, Interesting

      The idea is that you can split up the program in parallel tasks in a fully automated way. If you as a programmer even have to think about parallelizing, I’m sorry, but then your compiler is “doin’ it wrong” and your languages is from the stone age. ^^
      An a bonus, when you can completely rely on a function with the same input producing the same output, you can also throw caching in there algorithmically (where required, on-demand, whatever you wish)
      But bla... that is all just the stuff on the surface. Like explaining the pointlessness of “metaprogramming” when there stops being a difference between data and code.

      I find the most amazing thing about Haskell as it is today, is that things that need the addition of new constructs to the language and a big change in the compiler, are just your normal library in Haskell. It can look like a whole new language. But it’s just a library. And that is amazing!
      Then, when you get to the GHC extensions, things that are as much on the forefront of Informatics science as the LHC on physics, with everybody else copying it years later... Sorry, but if you like elegance in programming, ...I just have no words for it...

      The thing is, that it’s crazy hard to learn. Which is not a fault in language design. Because it’s very elegant. It’s simply the fact that it is so far ahead of anything in your everyday language. You won’t expect to sit in a spaceship and drive it like your car too, would you? Or program the LHC like a VCR.

      Yes, I am a fan. Even if I sometimes hate it for being so damn smart compared to me the normal programmer. But I became so much a better programmer in all other languages, it’s crazy.

      It’s simply a completely different class of skill. And that is why one should learn Haskell. Fuck the “Oh, we’re now only coding in Haskell” attitude. When you really understand the ideas behind it, every language becomes Haskell. And you can write practically bug-free programs of...

      Aaah, what am I saying. <John Cleese>Oh it’s driving me mad... MAD!</John Cleese> *slams cleaver into the table*
      *head developer comes in*
      Head developer: Easy, Mungo, easy... Mungo... *clutches his head in agony* the war wound!... the wound... the wouuund...
      Manager: This is the end! The end! Aaargh!! *stabs himself with a steel lambda sculpture*

      --
      Any sufficiently advanced intelligence is indistinguishable from stupidity.
    21. Re:Is it just me ? by j1m+5n0w · · Score: 4, Informative

      I would add a couple other "must have" features in functional languages:

      * The ability to pass a function as an argument to another function (i.e. higher order functions, like qsort in the C standard library).

      * Support for a points-free programming style in which things can be passed from one function to another without naming them.

      Some other features that perhaps aren't technically required but make functional programming a lot easier:

      * Closures, local function definitions, garbage collection, partial evaluation of function.

    22. Re:Is it just me ? by Anonymous Coward · · Score: 0

      Logging onto a message board implies a certain amount of not being a dick. There is no need to be such an enormous one.

    23. Re:Is it just me ? by ls671 · · Score: 1

      Interestingly enough, there is talks about implementing “soft tail call” and "“hard tail call” optimization in the JVM:

      http://blogs.sun.com/jrose/entry/tail_calls_in_the_vm

      --
      Everything I write is lies, read between the lines.
    24. Re:Is it just me ? by Anonymous Coward · · Score: 0

      In a proper functional language, there is no such thing as iteration. There can't be. The instant you say, "each time through the loop, increment the counter, and as soon as it hits this certain value stop," you have stopped programming in a functional style.

      Recursion basically does the same thing, albeit through function calls and argument passing. The difference is that it is "cleaner" because it's incredibly simple, and because there are no state changes. In Lisp languages you can just build your own looping constructs that use recursion under the hood, and get the best of both worlds.

      Of course the Lisp languages don't rigidly enforce a purely functional style like Haskell does, but if you want to program in a purely functional way, they certainly have the tools to do that. Actually, if you wanted to make your own parallel "Haskell" in Lisp, that would be possible since it excels at constructing metalanguages, and can make very quick foreign function calls to C/C++ libraries for multiprocessing or threading.

    25. Re:Is it just me ? by ascari · · Score: 5, Funny

      "recursive style" Definition: Curse. And then curse again.

    26. Re:Is it just me ? by Captain+Segfault · · Score: 0

      Well, yes, quicksort is slow in the worst case, which in the most naive implementations includes a sorted input. That isn't Haskell's fault, and you don't need iteration to implement something like median-of-3 which would fix the problem.

    27. Re:Is it just me ? by Anonymous Coward · · Score: 0

      This is comment is not +5 insightful its incorrect. You don't understand Ahmdal's Law. Any algorithm that is fundamentally iterative, in that in relies on the results of the last iteration, will quickly reach an upper limit of improvement by making it more multithreaded and adding more processors. Many, many algorithms are like this. Don't believe me? Just try parallelizing Dijkstras...

    28. Re:Is it just me ? by Anonymous Coward · · Score: 0

      What a great opportunity for a pizza analogy!

      I'll take mine deep-style, with a whole load of extra dick!

      Pizza analogy FTW!

    29. Re:Is it just me ? by DragonWriter · · Score: 1

      would add a couple other "must have" features in functional languages:

      * The ability to pass a function as an argument to another function (i.e. higher order functions, like qsort in the C standard library).

      Yeah, I'd agree that first-class functions are a requirement.

      * Support for a points-free programming style in which things can be passed from one function to another without naming them.

      I don't think this is a requirement for a language to be a functional programming language, though its certainly nice to have.

      Some other features that perhaps aren't technically required but make functional programming a lot easier:

      * Closures, local function definitions, garbage collection, partial evaluation of function.

      I'm not sure I'd put "local function definitions" in the nice-to-have category rather than the definitional; if functions are first class values, it would be, at a minimum, very odd not to be able to define them locally. Generally, though, I agree.

    30. Re:Is it just me ? by arevos · · Score: 1

      Yes, I realise all that. I was just pointing out that all functional languages use "recursive style", as ls671 puts it.

    31. Re:Is it just me ? by Anonymous Coward · · Score: 0

      Nobody cares what you think.

    32. Re:Is it just me ? by Anonymous Coward · · Score: 0

      To you "functional" means . . . who the fuck are you?
      Every other functional language out there has to call itself "mostly functional" nowadays because the Haskell guys have been such shits about claiming the term "pure functional" for themselves.
      It's bad enough without double-shits like you just making up your own definitions.

    33. Re:Is it just me ? by DragonWriter · · Score: 1

      So if we allow "non pure" functional languages to be "functional languages" then the whole notion of being functional becomes irrelevant.

      Not really. In fact, I think its much more useful to discuss the value of functional languages in terms of the benefits of specific features and differences of degree or, rather than just a binary categorization.

      Java can be considered a non-pure functional language.

      Sure, in the same sense that a pit of mud can be considered a non-pure body of water. Likewise, one can meaningfully differentiate between the non-pure functional status of Java, the non-pure functional status of Scheme, and the non-pure functional status of Erlang, and the effects of those on their utility for various programming applications, just as one can meaningfully differentiate between the non-pure water of the aforementioned mud pit, that of a somewhat silty river, and that of a fairly clear mountain lake, and the effects of those differences on their utility as a source of drinking water.

    34. Re:Is it just me ? by oldhack · · Score: 1

      I'm lost. And then what?

      --
      Fuck systemd. Fuck Redhat. Fuck Soylent, too. Wait, scratch the last one.
    35. Re:Is it just me ? by Anonymous Coward · · Score: 0

      Except of course when you add "par" and "seq" to Haskell you fundamentally change it's semantics. Haskell semantics are non-strict, but "par" changes that as you may evaluate expressions that you don't use -- i.e. it's no longer non-strict ..

    36. Re:Is it just me ? by Pseudonym · · Score: 1

      Exactly.

      Erlang actually owes more to Linda and Prolog than to languages that we usually think of as "functional" (like the Lisp/Scheme family and the ISWIM family). But still, Erlang is functional in the same way that Java is object-oriented and C++ is generic.

      If you've ever programmed in a "true" object-oriented language, like Smalltalk or Eiffel, Java seems clunky. If you've ever used a programming language with "true" parametric polymorphism, like ML or Haskell, C++ seems clunky. (Actually, they seem clunky even if you haven't, but that's another story.)

      It makes sense to say that Java supports object-oriented programming and C++ supports parametric polymorphism. Erlang supports functional programming in the same way.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    37. Re:Is it just me ? by SparafucileMan · · Score: 1

      This is also known as the No Free Lunch Theorem and traces right back to Godel, Turing, and the foundations of all mathematics. You are right, it certainly isn't going anywhere.

    38. Re:Is it just me ? by Anonymous Coward · · Score: 1, Funny

      Car analogies are simpler.

    39. Re:Is it just me ? by Anonymous Coward · · Score: 0

      Then why aren't the FP shops kicking as and taking names? They should be leading in every segment of the market if what you wrote is true. It isn't. This is because FP isn't this magical pixie dust that so many claim it to be. That the compilers produce extremely slow code doesn't help matters. It really doesn't matter if your code runs on 8 processors if the C version is 10x faster on a single core.

    40. Re:Is it just me ? by jensend · · Score: 2, Informative

      You misunderstand what he means by "getting past" Amdahl's Law. That wouldn't involve somehow changing the fact that only speeding up part of a program can only do so much to speed the whole program- it'd involve radically changing the proportion of various algorithms which can be parallelized. For instance, if somebody were to come up with a constructive proof that P=NC that'd certainly do the trick (though most people's guess is that that's false).

    41. Re:Is it just me ? by rjh · · Score: 1

      You're correct when you say that if you parallelize 50% of your algorithm, you still have to deal with the other 50%. However, new theoretical discoveries are made all the time in algorithm design; new theoretical advances may result in an equivalent algorithm that's 90% parallelizable.

      Amdahl's Law is a strong mathematical constraint on the maximum improvement in performance for a particular algorithm. In order to get past Amdahl's Law, use a different algorithm.

      I freely confess to having used "get past Amdahl's Law" in a pretty loose and informal sense, though, so as to avoid that digression. :)

    42. Re:Is it just me ? by abigor · · Score: 1

      Actually, it's because functional programming is hard and not typically taught well in school. People learn imperative languages first, and tend to end up thinking that way. Lots of functional languages such as O'Caml compile to very fast runtimes.

    43. Re:Is it just me ? by bertok · · Score: 2, Insightful

      Amdahl's law is not like Moore's "law". Amdahl's law is an observation of mathematics. You can't ever get around the fact that if you increase the performance of 90% of the instructions in a program, you still have to deal with the other 10%. Even if you increase the performance of 90% of the instructions by 100x or something large, if the other 10% take a long time (like disk access) its going to kill your performance.

      It makes the implicit assumption that there is a '10%'. The whole point of some pure functional languages is that essentially all of it can be parallelized, 99% or more in some cases. There are programs where the sequential part is 0.001%, if that.

      However, another comeback I've heard is that the "end goal" of parallelization is not necessarily to do the same thing in less time, but to do more in the same time. That is, you increase the "parallelizable" bit while keeping everything else constant. For example, take a look at computer games, where you'd just do "higher resolution", or "bigger textures", or "more complex shaders". You do more, while the sequential stuff stays much the same.

      I can't stand it when people trot out Amhdal's law like it's some sort of reason that parallelization is futile or something. It's missing the point completely!

    44. Re:Is it just me ? by Anonymous Coward · · Score: 0

      You won’t expect to sit in a spaceship and drive it like your car too, would you?

      Why not?

      As the pilot, my wishes are simple: I want to move up and down and backward and forward. Why shouldn't the system abstract complex functionality to allow me to do this easily?

      Assembly code is much more difficult than Haskell. Are you suggesting it should be otherwise?

    45. Re:Is it just me ? by microbox · · Score: 1

      The idea is that you can split up the program in parallel tasks in a fully automated way. If you as a programmer even have to think about parallelizing, I’m sorry, but then your compiler is “doin’ it wrong” and your languages is from the stone age.

      This is not true in high-performance computing. If you don't want your CPU spinning its wheels on locks and cache misses, then you need to go quite low level -- and really think about the data structures you're using, and how to parallise tasks with next to no interthread communication.

      --

      Like all pain, suffering is a signal that something isn't right
    46. Re:Is it just me ? by Anonymous Coward · · Score: 0

      think it over for a minute retard. There is no "pure functional" programming because it would be optimized back to a single, constant value, which is thrown away. To be anything more than math masturbation, you need input and output, which are non functional.

    47. Re:Is it just me ? by Anonymous Coward · · Score: 0

      Functional languages do support iteration. It is just implemented as internal vs. external iteration. Both are valid forms and not unique to functional languages (e.g. Smalltalk used them). Side-effects are always necessary and must be handled and pure OO doesn't have anything inherently incompatible, just that the OO implementations that we use are far from pure.

      You never get "past" Amdahl's Law, no matter how loosely you want to state it. A change in algorithms doesn't work around it, it just changes the variable values. Instead of fighting Amdahl's law head-on you must change your perspective to focus on Gustafson's law instead.

    48. Re:Is it just me ? by shutdown+-p+now · · Score: 1

      First of all, for a language to be called "functional", you need first-class functions (duh). What this means is that a function is "just another value" - it can be passed around in function arguments and returned, assigned/bound to a variable, and so on. But this also generally means first-class "function literals" - anonymous functions, lambdas, and so on - and for that you need closures. Furthermore, once you get closures and function-typed return values, you have to have some form of automatic memory management - how else will you know when to release the variables captured by a particular closure when it is released itself (and keep in mind that closures and their captures can form circular references)?

      Partial application can then be considered syntactic sugar for anonymous functions, and so can local function definitions (treat them as function values bound to local variables).

    49. Re:Is it just me ? by unitron · · Score: 2, Funny

      See: Recursive

      --

      I see even classic Slashdot is now pretty much unusable on dial up anymore.

    50. Re:Is it just me ? by swillden · · Score: 1

      The idea is that you can split up the program in parallel tasks in a fully automated way. If you as a programmer even have to think about parallelizing, I’m sorry, but then your compiler is “doin’ it wrong” and your languages is from the stone age.

      This is not true in high-performance computing. If you don't want your CPU spinning its wheels on locks and cache misses, then you need to go quite low level -- and really think about the data structures you're using, and how to parallise tasks with next to no interthread communication.

      The point of functional programming is that you don't have to think about locks or how to manage contention on your data structures because there is no such thing such thing as mutable data. And if you're just letting the compiler do the parallelization, you don't have to think about interthread communication, either, because the compiler will automatically find the places where function calls can be parallelized with zero interthread communication. Of course, if you structure your code so that it's inherently sequential then the compiler won't find any opportunities for parallelization, so you still have to think about that.

      Of course, functional code ultimately gets translated to imperative code, because that's what our processors do. And that translation is being done by a program, which means it will never match the best that a talented human can do, in much the same way that hand-coded assembler, produced by a developer who knows the processor inside and out, will always beat the best-optimizing C compiler. But with functional programming, a good compiler can take significant advantage of multi-core systems for much less programmer effort. Is it as good at maximizing performance? Obviously not. But it's quite good, at much lower cost.

      --
      Note to ACs: I usually delete AC replies without reading them. If you want to talk to me, log in.
    51. Re:Is it just me ? by [KERNEL32]_ · · Score: 1

      AFAIK, Lua have all these features and is not a functional language (although some people programs functionally with it). These features are just required for any modern procedural language...

    52. Re:Is it just me ? by Anonymous Coward · · Score: 0

      Basically, a subset of what Scheme had 30 years ago in the MIT AI lab.

    53. Re:Is it just me ? by Belial6 · · Score: 1

      Obviously your wrong because of the law of thermodynamics.

    54. Re:Is it just me ? by Alpha830RulZ · · Score: 1

      And Scala would be the same. The Odersky book describes it as a hybrid, but the force of the language is functional in nature. I'm not intimate with Erlang, but I think most knowledgeable commentators would use almost identical words for Scala as you use for Erlang. It does allow mutables, but de-emphasizes them. It treats functions as first class objects. Recursion is the preferred approach to repetition. There may be some higher canonical definition that it violates, but it looks pretty functional to me. And if you haven't tried it yet, it's pretty cool. It achieves some of the conciseness of Python, gives you java byte code as output, so it integrates into existing work easily, and lets you leverage any java libraries you have.

      --
      I was taught to respect my elders. The trouble is, it's getting harder and harder to find some.
    55. Re:Is it just me ? by syousef · · Score: 1

      Facebook developed their real-time chat application in Erlang

      Do you normally like to make your opponent's point for them? Facebook chat is horrible and buggy in my experience. Messages go missing. It freezes Firefox. It's just plain awful!

      --
      These posts express my own personal views, not those of my employer
    56. Re:Is it just me ? by Anonymous Coward · · Score: 0

      Haskell's syntax is worse than C's. If someone could do the same for functional programming that Python does for the imperative (side-effect) languages ...
      And by the way one can write imperative code in Haskell

    57. Re:Is it just me ? by rjh · · Score: 1

      Right -- I'm also including such things as discovering new equivalent algorithms that offer better parallelization fractions, too. Theory is great: it offers the potential for both revolutionary (P=NC) and evolutionary ("hey, I wonder if...") improvements.

    58. Re:Is it just me ? by Anonymous Coward · · Score: 0

      I don't know of any widely used multi-threaded GUI kit.

      BeOS, and unsurprisingly enough it does indeed use asynchronous message passing.

    59. Re:Is it just me ? by smallfries · · Score: 1

      Of course, functional code ultimately gets translated to imperative code, because that's what our processors do. And that translation is being done by a program, which means it will never match the best that a talented human can do, in much the same way that hand-coded assembler, produced by a developer who knows the processor inside and out, will always beat the best-optimizing C compiler.

      If you are thinking of the functional effects of the code then it makes sense to consider it as instructions in an imperative model, but for maximising performance on a modern processor this is a really bad way to think of it. This is one of the main reasons that superscalar processors get a bad rep in terms of understanding the performance effects of different sequences. Once you take into account the re-ordering that the processor is free to do you no longer have an imperative sequence of instructions, rather you have a data-flow graph containing a set of "pure" instructions. The first point is that functional code maps into this setting much better than imperative source code, and the second point is that a compiler can organise that flow graph much more effectively than a human programmer.

      Sure, a good programmer can beat the best C compiler - but the problem is not that a compiler can't write good code, the problem is that C is a horrific handicap that holds back the code generator. If you relax the constraints on the source language then the human won't stand a chance.

      --
      Slashdot: where don knuth is an idiot because he cant grasp the awesome power of php
    60. Re:Is it just me ? by Hurricane78 · · Score: 1

      My argument is, that you can put this thoughts into general transformational formulas, and put them in the compiler. :)

      I might be wrong, but at least I will try and find out / prove it. :)

      --
      Any sufficiently advanced intelligence is indistinguishable from stupidity.
    61. Re:Is it just me ? by microbox · · Score: 1

      The point of functional programming is that you don't have to think about locks or how to manage contention on your data structures because there is no such thing such thing as mutable data.

      Great, now you get a whole bunch of cache misses, and your CPU is sitting at 10%.

      --

      Like all pain, suffering is a signal that something isn't right
    62. Re:Is it just me ? by sergueyz · · Score: 1
      Scala does not scale comparing with Erlang/Haskell. F# also shouldn't, because it uses .Net (see C# up there).

      Also, Nested Data Parallelism won't be available in programming languages sooner that in Haskell. And I look for NDP as an unique way to make heterogenous parallel environments work (those like IBM Cell BE, for example).

    63. Re:Is it just me ? by Goaway · · Score: 1

      That was not the point. The point was that this implementation of quicksort is bad. It could be argued it is not even a true quicksort.

    64. Re:Is it just me ? by bondsbw · · Score: 1

      Obviously your wrong because of the law of thermodynamics.

      Yes, because this has something to do with thermal equilibrium, conservation of energy, perpetual motion machines, or cooling stuff to absolute zero.

      In case you are confused, Wikipedia has a link for that.

      --
      All my liberal friends think I'm a conservative, all my conservative friends think I'm a liberal.
    65. Re:Is it just me ? by swillden · · Score: 1

      The point of functional programming is that you don't have to think about locks or how to manage contention on your data structures because there is no such thing such thing as mutable data. Great, now you get a whole bunch of cache misses, and your CPU is sitting at 10%.

      Actually, cache utilization by functional programs tends to be excellent. The compiler optimizes most of the duplication of data away in tight loops, so where it matters for performance, data actually is modified in place.

      Really, you should learn something about functional programming before dismissing it.

      --
      Note to ACs: I usually delete AC replies without reading them. If you want to talk to me, log in.
    66. Re:Is it just me ? by swillden · · Score: 1

      Very interesting post. Thanks.

      --
      Note to ACs: I usually delete AC replies without reading them. If you want to talk to me, log in.
    67. Re:Is it just me ? by Anonymous Coward · · Score: 0

      Maybe you don't know about the ! operator, but it is a "strictness operator", and is a part of Haskell 98. Computations immediately following a ! are computed strictly.

    68. Re:Is it just me ? by Belial6 · · Score: 1

      His wrongness was obviously powered by the the massive wind generated by my sarcasm flying over your head. That's what the "Whoosh" sound you heard was.

    69. Re:Is it just me ? by ais523 · · Score: 1

      Look up concatenative languages, such as Joy (http://www.latrobe.edu.au/philosophy/phimvt/joy.html); I wrote Underload (http://esolangs.org/wiki/Underload) as a sort of minimal expression of the same idea. Both of those languages effectively allow you to create arbitrary first-class functions despite having no form of function literal, and no concept of a closure, and work fine without garbage collection. However, doing things that way you have to do things differently from more standard functional programming languages.

      --
      (1)DOCOMEFROM!2~.2'~#1WHILE:1<-"'?.1$.2'~'"':1/.1$.2'~#0"$#65535'"$"'"'&.1$.2'~'#0$#65535'"$#0'~#32767$#1"
    70. Re:Is it just me ? by shutdown+-p+now · · Score: 1

      I've taken a brief look at Joy, and it seems to me that quotation/dequotation is not fundamentally different from eval (or did I miss something?). While eval can technically be considered a way to construct functions as first-class values, it isn't traditionally considered truly "first-class" - otherwise the combo of ANSI C + libtcc, for example, could also be said to be "first-class functional".

      Also note that I didn't mention "garbage collection" - I merely talked about "automatic memory management", which is broader. In fact, even there I was kinda wrong, because in a language where identifiers are bound to values, not mutable locations (e.g. Haskell), a lambda can just copy the values on capture. In Joy, so far as I can see, there isn't any lexical scope to speak of in the first place, so there's simply nothing to capture / close over - so of course there are no management issues (at least with first-class functions), either.

    71. Re:Is it just me ? by Abcd1234 · · Score: 1

      * Support for a points-free programming style in which things can be passed from one function to another without naming them.

      I'm utterly baffled you put this in the list. AFAICT, points-free programming in haskell is nothing more than a nifty curiosity, and *certainly* not "must-have". Honestly, how is:

      func = a . b

      Any better than

      func x = a $ b x

      ? Hell, I often find points-free formulations *more* confusing, in general, than an equivalent, explicit formulation.

    72. Re:Is it just me ? by Captain+Segfault · · Score: 1

      That was not the point. The point was that this implementation of quicksort is bad. It could be argued it is not even a true quicksort.

      I'm assuming that that this implementation of quicksort is one which calls filter three times and recursively calls itself twice. Sure, that's inefficient as far as good quicksorts go. It's still a quicksort.

      My point is that the "slowness" of "qsort [1..10000]" has almost nothing to do with the qsort not using iteration and everything to do with [1..10000] being a pathological worst case for naive quicksort. It is not complicated to fix that.

    73. Re:Is it just me ? by Anonymous Coward · · Score: 0

      It makes the implicit assumption that there is a '10%'. The whole point of some pure functional languages is that essentially all of it can be parallelized, 99% or more in some cases. There are programs where the sequential part is 0.001%, if that.

      The problem is that even 99% parallelizable code is not good enough to utilize a traditional SMP once the core count is increased sufficiently. Asymmetrical or dynamical multicore chips would be more useful in such a situation. Perhaps the OpenCL people are on to something here but there would be still be a lot of room for improvement, both in hardware and software.

      I do agree that the dataparallel approach is useful today (doing more in the same time) and in the future. I think most people, when they are talking about the problem of parallelism, are feeling the pain of improving the performance of their algorithm of interest, nothing more. That view really doesn't take the other parts of the system or "the experience" into consideration.

    74. Re:Is it just me ? by j1m+5n0w · · Score: 2, Informative

      I guess I was thinking more of the fairly universal concept that you can use the result of one function as an argument to another without giving it a name. For instance:

      result = f(g(x))

      instead of

      foo = g(x); result = f(foo)

      Haskell applies a points-free style in more cases than we're used to seeing in other languages, which is sometimes useful but I agree it is just as often an annoyance to those who are trying to understand someone else's code. I was thinking of a rather looser definition of points-free, which is present to some degree in all the programming languages I'm familiar with.

    75. Re:Is it just me ? by Abcd1234 · · Score: 1

      Sounds to me like your definition of "pointsfree" is *way* too broad. Wikipedia's article on the topic (which refers to it as 'tacit programming') describes it as:

      a programming paradigm in which a function definition does not include information regarding its arguments, using combinators and function composition (but not -abstraction) instead of variables.

      Which bears only a superficial resemblance to what you're describing. And as you say, your definition would apply to virtually every programming language on the planet. As such, it seems pretty... well... pointless. :)

  2. Amazing day... by AnotherShep · · Score: 4, Funny

    And all three of its users are overjoyed.

    1. Re:Amazing day... by Anonymous Coward · · Score: 0

      You mean there are *that* many?!!!

    2. Re:Amazing day... by acheron12 · · Score: 1

      It's surprisingly popular on Project Euler.

      --
      there is no god but truth, and reality is its prophet
    3. Re:Amazing day... by Anonymous Coward · · Score: 0

      No it has three users but they register a thousand handles each on popular sites and spend their time telling normal people that they would be so much happier if they embraced the Haskell.

    4. Re:Amazing day... by Anonymous Coward · · Score: 0

      ever been to reddit? proggit is full of haskellers

    5. Re:Amazing day... by Anonymous Coward · · Score: 0

      You're absolutly right. Who needs anything besides BASIC.

    6. Re:Amazing day... by Hurricane78 · · Score: 1

      Yeah, and you may thank them when attached to a heart-lung machine that was NOT written in C/C++ instead, because B. Curry’s gonna kick yo ass with that attitude! ;P

      --
      Any sufficiently advanced intelligence is indistinguishable from stupidity.
    7. Re:Amazing day... by Anonymous Coward · · Score: 0

      ever been to reddit? proggit is full of haskellers

      "proggit" is also full of brainless high school kids and college students who can't program their way out of a paper bag.

      The popularity of Haskell on proggit has more to do with the aforementioned group wanting to be trendy than it does with the actual use of Haskell for anything non-trivial.

    8. Re:Amazing day... by Anonymous Coward · · Score: 0

      Yeah, and you may thank them when attached to a heart-lung machine that was NOT written in C/C++ instead, because B. Curry’s gonna kick yo ass with that attitude! ;P

      I hear this all the time on slashdot and really think it is misinformed. Honestly, how many pieces of medical equipment have their software written in Haskel or any of of the similar language? These devices more often than not use an embedded OS (or more and more Linux these days) with C or C++ applications.

      Perhaps there is some researchers using these languages or the rare piece of gear, but in industry the old standby system languages are still king. Don't agree...take a look at the Jobs boards for Phillips, Siemens, Nihon Koden, GE Healthcare, Welch Allen, and other healthcare equipment manufacturers and see the skills they are looking for. I'm talking about patient monitors, diagnostic cardiology equipment, CT, MR, digital x-ray, Anesthesia machines, ventilators, invasive cardiology suites, bone densitometers.

    9. Re:Amazing day... by Zeroko · · Score: 1

      I once wrote a lambda-calculus evaluator in QBASIC (before I heard of Scheme & later Haskell), so I guess so. :)

    10. Re:Amazing day... by RegularFry · · Score: 1

      I do know of a vehicle braking system that was coded in C, but the C was generated by a Haskell code generator. I wouldn't be at all surprised if that sort of thing was quite common.

      --
      Reality is the ultimate Rorschach.
    11. Re:Amazing day... by Anonymous Coward · · Score: 0

      Hax my dead dog.

  3. Not to sound like an ass, but... by XPeter · · Score: 1

    What the hell have these guys been doing for the past four years? Only now they are implementing DoAndIfThenElse/EmptyDataDeclarations

    Is this the Slackware of the programming world?

    --
    "The difference between genius and stupidity is that genius has it's limits" - Albert Einstein
    1. Re:Not to sound like an ass, but... by xZgf6xHx2uhoAj9D · · Score: 1

      Those things were implemented many years ago. The new standard only standardizes features which have been stable in multiple implementations for years. That's how standards are supposed to work.

    2. Re:Not to sound like an ass, but... by Ann+Coulter · · Score: 1

      Moreover, the DoAndIfThenElse extension merely extends the "do" syntax with if/then/else clauses; it is syntactic sugar. Empty data declarations are essentially union types unioned over no labels and therefore can have no values except for the bottom value.

      References:
      http://hackage.haskell.org/trac/haskell-prime/wiki/DoAndIfThenElse
      http://hackage.haskell.org/trac/haskell-prime/wiki/EmptyDataDecls

    3. Re:Not to sound like an ass, but... by Anonymous Coward · · Score: 0

      DoAndIfThenElse isn't a new feature; it just addresses some unintuitive syntax when using multiline "if-then-else" forms in a "do" block.

      EmptyDataDeclarations allows for data types without a constructor... but to be perfectly honest I haven't quite figured out what practical benefit they have :). I'm sure there is a reason, but I don't think it's as trivial or obvious as you make out.

    4. Re:Not to sound like an ass, but... by ascari · · Score: 3, Insightful

      The fact that union types can have no values explains a lot about Jimmy Hoffa.

    5. Re:Not to sound like an ass, but... by Pseudonym · · Score: 2, Interesting

      EmptyDataDeclarations allows for data types without a constructor... but to be perfectly honest I haven't quite figured out what practical benefit they have :). I'm sure there is a reason, but I don't think it's as trivial or obvious as you make out.

      Consider the tag struct idiom in C++:


      struct open_read_t {};
      struct open_read_write_t {};

      class File {
              File(const string& name, open_read_t); // Open for reading.
              File(const string& name, open_read_write_t); // Open for writing.
      };

      The tag structs are not used to carry data; their only purpose for existing is to disambiguate the two constructors.

      Similarly, in the STL, tag structs are also used to mark iterator categories, to make sure that when you could use more than one algorithm for a container, the most appropriate one is selected.

      This is essentially what empty data declarations are for in Haskell, except that by having no constructors, you can guarantee that they will never be instantiated. The most common use is in conjunction with phantom types.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    6. Re:Not to sound like an ass, but... by Anonymous Coward · · Score: 0

      Check out "Fun with Functional Dependencies". I think ExistentialQuantification is a better pattern for organizing code, but FunDeps can potentially improve run-time performance.

    7. Re:Not to sound like an ass, but... by iluvcapra · · Score: 1

      I'm a union type and have complex values, you insensitive clod!

      --
      Don't blame me, I voted for Baltar.
  4. Reminds me of Life of Brian... by migla · · Score: 2, Funny

    "The current committee is still discussing how to go about finding a new committee"

    A fitting name for this Haskell programming language might have been "Python" hadn't it all ready been taken.

    --
    Some of my favourite people are from th US; Vonnegut, Chomsky, Bill Hicks.
    1. Re:Reminds me of Life of Brian... by schon · · Score: 3, Funny

      A fitting name for this Haskell programming language might have been "Python" hadn't it all ready been taken.

      Actually, naming it "Python" would be doubly-fitting.. in fact, I think we should rename *all* programming languages "Python", just so it doesn't get confusing :)

    2. Re:Reminds me of Life of Brian... by acheron12 · · Score: 5, Funny

      Welcome to the programming language department. Bruce here teaches Python, the object oriented dynamically typed language. Bruce teaches Python the lazy functional language, while Bruce teaches postfix Python. And then there's Bruce who teaches s-expression Python and is in charge of the snake dip.

      --
      there is no god but truth, and reality is its prophet
    3. Re:Reminds me of Life of Brian... by Pseudonym · · Score: 2, Funny

      Well that's one way to ensure that Python retains lambdas, map and filter.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
  5. But I'm lazy... by nweaver · · Score: 5, Funny

    So I don't think I'll look at the article until I actually need to program in Haskel....

    --
    Test your net with Netalyzr
    1. Re:But I'm lazy... by AlgorithMan · · Score: 1, Redundant

      you could do a lazy evaluation of TFA...

      --
      The MAFIAA is a bunch of mindless jerks who will be the first up against the wall when the revolution comes
    2. Re:But I'm lazy... by Ma8thew · · Score: 4, Insightful

      That might be the joke.

    3. Re:But I'm lazy... by AlgorithMan · · Score: 1

      dang, you're right *selfpwned*

      --
      The MAFIAA is a bunch of mindless jerks who will be the first up against the wall when the revolution comes
    4. Re:But I'm lazy... by Hurricane78 · · Score: 1

      But learning Haskell is only in a small part about writing Haskell. It’s mainly about getting to the next level in programming skill. And becoming much better in every language.

      Besides: Want to earn some big money for doing actual “mission-critical” software, that lives depend on, and that really means something? There’s no way to do serious business like that without Haskell, and not go crazy. ^^

      So there you go. If you want to continue doing basically a front-end to a database on color mixing machines, or a sales system, to earn enough to live, then go ahead, continue doing C++/Java/Delphi. :)

      --
      Any sufficiently advanced intelligence is indistinguishable from stupidity.
    5. Re:But I'm lazy... by Anonymous Coward · · Score: 0

      Sorry, I only read jokes when there's someone to listen to me laugh

    6. Re:But I'm lazy... by swillden · · Score: 1

      He evaluated the joke lazily, too. Slashdot posts don't really count as output.

      --
      Note to ACs: I usually delete AC replies without reading them. If you want to talk to me, log in.
    7. Re:But I'm lazy... by Spacezilla · · Score: 1

      So there you go. If you want to continue doing basically a front-end to a database on color mixing machines, or a sales system, to earn enough to live, then go ahead, continue doing C++/Java/Delphi. :)

      Will do, thanks. The pay is ridiculously high considering how little is required of the brain. :)

  6. Concurrency? by qmaqdk · · Score: 1

    I skimmed through the revisions, and I don't see how they relate to concurrency (caveat I'm a Haskell newbie). Maybe someone can enlighten me.

    --
    My UID is prime. Hah!
    1. Re:Concurrency? by AnotherShep · · Score: 4, Funny

      They figure if they make it good enough, more than one person will code in it at a time.

    2. Re:Concurrency? by Lemming+Mark · · Score: 4, Insightful

      Well, pure functional languages are (potentially) good for concurrency in general. Because they have no mutable variables in the usual sense, it doesn't actually matter what order functions are evaluated in (other than the fact that callers cannot continue until their callees return). You can't do this in C or Java because it might be necessary for one function to see a variable modified by another. In a functional language, any dependencies are explicit call-return relationships (well, ish, they typically do have some non-functional constructs otherwise it's hard to do IO!), so in principle it's quite easy to split up a program's work across multiple CPUs (or machines) and not worry about whether they need to talk to each other.

      Haskell, along with the ML family of languages, also has an amazing type checker that is waaay more sophisticated than most other languages. I think most people who've played around with these languages do start to feel that often "If it compiles, it's bug-free". Obviously that's not something you can rely on, since the compiler can't know what you meant to do. But it is true that the type system is *way* more useful at detecting bugs at compile-time than for any conventional language I've used.

    3. Re:Concurrency? by xZgf6xHx2uhoAj9D · · Score: 1

      Yeah the revisions are really tiny (well except for FFI, which also doesn't relate to concurrency). I think the Slashdot poster was trying to say that Haskell in general is nice for concurrency, not these revisions specifically.

      With the exception of FFI, these revisions are dreadfully boring. It would be like if a new C standard came out that allowed you to write "floating" instead of just "float". That's about on par with the magnitude of the changes Haskell 2010 brings in :P

    4. Re:Concurrency? by Anonymous Coward · · Score: 0

      Ha! Sadly, I wasted my last mod points on some jibberish about graphics cards.

    5. Re:Concurrency? by j1m+5n0w · · Score: 1

      The announcement is perhaps a bit less interesting than the summary would have you believe... The most recent Haskell standard was Haskell 98, eleven years ago. A new committee was formed to bring the standard up to date with current implementations. Most of the changes listed have been in GHC and other implementations for some time now, and none of them appear to have anything to do with concurrency directly. (Which isn't to say that interesting stuff hasn't been happening in the Haskell world in that area, it just doesn't directly affect the core language.)

    6. Re:Concurrency? by radtea · · Score: 3, Interesting

      Well, pure functional languages are (potentially) good for concurrency in general. Because they have no mutable variables in the usual sense, it doesn't actually matter what order functions are evaluated in (other than the fact that callers cannot continue until their callees return).

      Maybe you can help me get past one of my mental stumbling-blocks with Haskell, which seems like a really cool language, but which I clearly have no clue about because I don't get a very fundamental thing. As I understand it there are two fundamental claims about Haskell:

      1) it is a "pure functional" language, which is therefore entirely and completely and "purely" side-effect-free. I appreciate the immense potential value of this for things like program verification, and I'd love to learn more about it.

      2) there is a Haskell construct that is part of the Haskell language called a "monad" that can have side-effects.

      I'm a deeply pedantic guy, and I'm unable to reconcile these two claims, and it puts me off looking more deeply into the language every time I read about it because there's clearly something I don't get. It seems to me that either:

      a) Haskell is not actually purely functional: it is a purely functional core sub-language with extremely well controlled additional side-effect-producing parts

      b) Monads are not actually considered "part" of the Haskell language, in the same way that pre-standardization STL was not "part" of the C++ language.

      c) I'm completely missing something.

      Enlightenment would be greatly appreciated.

      --
      Blasphemy is a human right. Blasphemophobia kills.
    7. Re:Concurrency? by Lemming+Mark · · Score: 1

      Heh, to be honest I'm mostly in the same boat as you - how can Haskell do side-effect stuff whilst still being purely functional. And what on earth is a Monad!?

      A programmer friend of mine used to say that using monads to emulate state would be a bit like the following: imagine you want to emulate state but you're programming functionally. You want variables but you can't have them. Instead you have a big tuple of values representing the contents of all the "variables" and you pass this tuple to every function call and get back a new version with the variables updated. You're still programming purely functionally but you've got this emulation of mutable state.

      But I mentioned this to another friend who has a PhD in compsci, specialising in compiler design and he looked at me like I was insane - so apparently that's not a good representation of how they behave. Still, it at least gets you a feel for how you could have imperative constructs like variables without breaking the rules of pure functional programming. Maybe that makes the idea of monads seem a little less impossible, even if it doesn't help explain how they work?

      Other "functional" languages actually have an imperative subset (e.g. ML has variables, loop constructs, etc). Haskell is distinguished from those partly by being purely functional, so I presume that it really *is* purely functional by some definition, including the monads. But I can't say I understand how.

      I had to study the type system of ML as an undergrad and it had this property of looking really opaque to me until I'd stared at it for hours and hours, then suddenly I went "Ooooh, I see!". Monads have a similar feel to me but I've never taken the time to stare them down. That said I imagine that, like the ML type system, they're much easier to use than to fully understand.

    8. Re:Concurrency? by Anonymous Coward · · Score: 0

      The IO monad is implemented as

      type IO a = World -> (a,World)

      so that

      print :: String -> IO ()

      is implemented as

      print str world = world { stdout = stdout++str }

      i.e. print takes the world and returns the modified world.

      Maybe that's the way it's defined, but if an implementation doesn't do it exactly that way it's just an optimisation.

    9. Re:Concurrency? by Anonymous Coward · · Score: 0

      Well, none of a b or c are quite right, though "a" is closest. "c" is not right because you're only *somewhat* missing something :)

      Monads in haskell are pure. The IO monad lets you paste together IO values in a way that they remain opaque.

      Where the magic happens is that the 'main' function has type 'IO ()', which is probably actually a bunch of actions pasted together as above. Now, the *runtime* is the one that calls main. It gets the 'IO ()' back and executes it. The runtime is *not* functional, in fact GHC's runtime is written in C. And it's not haskell either, so haskell is actually pure.

      One practical result is that actions in haskell are values like any other. This is incredibly useful. For instance, just one thing, is that you can write your own control structures. But you can do a lot of other things once you can pass actions around.

    10. Re:Concurrency? by radtea · · Score: 1

      Monads in haskell are pure. The IO monad lets you paste together IO values in a way that they remain opaque.

      After staring at this explanation for fifteen minutes I feel deep sympathy for the people on /. who try to understand my comments on physics, because I imagine they make as little sense to them as this does to me :-D

      I think I kind of understand what you're saying: a monad is created on-the-fly by the (non-Haskell) runtime as an immutable object.

      I'm still tempted to quibble at the difference between "opaque" and "side effect free". Hidden side effects are still side effects, although I guess so long as they truly are opaque then the formal constraints on the language are still enforceable, and one gets the power of pure functional programming out of it.

      That's what I really wasn't understanding: Haskell does let you create side effects. But it is still a "pure functional" language in the sense that the side effects are implemented in such a way that you can still analyze Haskell programs as pure functional programs, because the side effects that Haskell lets you create are entirely hidden from the universe that Haskell knows about.

      So, to pay you back with an obscure comment from my own area of expertise: it's a bit like our universe being strictly causal under SR, but QM still being able to have acausal spooky actions at a distance. That's an analogy I can get behind.

      --
      Blasphemy is a human right. Blasphemophobia kills.
    11. Re:Concurrency? by shutdown+-p+now · · Score: 1

      Haskell, along with the ML family of languages, also has an amazing type checker that is waaay more sophisticated than most other languages. I think most people who've played around with these languages do start to feel that often "If it compiles, it's bug-free". Obviously that's not something you can rely on, since the compiler can't know what you meant to do. But it is true that the type system is *way* more useful at detecting bugs at compile-time than for any conventional language I've used.

      Actually, I dare say that Haskell type system is in fact a much bigger deal than its purity or laziness. Type classes are an awesome generalization of OO interfaces that let one define virtually arbitrary operators in a generic way, and then define generic algorithms using those operators, in an entirely type-safe way (and not using the C++ template model of "macros with a quick sanity check at declaration point and horrible error messages if anything goes wrong later"). They can be used to fully emulate conventional OO in fact. Then there are higher-order types, which let you reuse operations on types just as you use functions to reuse operations on values.

      Not to forget GHC extensions to Haskell, which let you control how exactly types are generalized - to consider what this means, try defining a generic function in C++, Java or C# that takes a collection of objects, which must all be instances of any class C implementing interface I - but they must all be instances of that same class (and not, say, some instances of C1 and some instances of C2, both implementing I).

    12. Re:Concurrency? by Zeroko · · Score: 1

      A monad is a construction that hides all the tuple-passing so that the program is more readable. E.g. code using the IO monad passes an object of type World from one line to the next without having to explicitly write it as an argument. It looks like procedural code (such as do x <- getLine ; putStrLn ("Greetings, " ++ x)), but instead of messing with the world in the background the world gets passed around as just another value.

      Speaking of physics...too bad we cannot make copies of the world, do computations in each, & then combine the different instances in various ways, or we could program time travel (among other things).

    13. Re:Concurrency? by mandolin · · Score: 1

      they have no mutable variables in the usual sense ... You can't do this in C or Java because it might be necessary for one function to see a variable modified by another.

      I think the key word here is "might".

      Nothing prevents a C compiler from figuring out "int foo(int a) { return a + 2; }" is pure. In fact gcc can do this to some extent; the relevant compiler flag (enabled by default w/optimization) is "-fipa-pure-const".

      gcc also lets you specify the attribute 'const' to declare that a function is pure (in the sense that we're using it here).

      Sure, it's coarse, and an afterthought, but it's also flexible.

    14. Re:Concurrency? by Kingrames · · Score: 1

      Damn, all the parallellizing stuff is built around that assumption. well, there goes that.

      --
      If you can read this, I forgot to post anonymously.
    15. Re:Concurrency? by Anonymous Coward · · Score: 0

      I've a little experience with Haskell. I've had to change my attitude from "If it compiles, it's bug-free" to "If it compiles and stops in finite time, it's bug-free".

    16. Re:Concurrency? by poopdeville · · Score: 1

      Heh, to be honest I'm mostly in the same boat as you - how can Haskell do side-effect stuff whilst still being purely functional. And what on earth is a Monad!?

      Monads are tricky to explain, kind of. I am going the abstract mathematical route, based on topology. Like most people, there are probably some things you will do only while you are in your home. And there are some things that you will only do outside of your home. Now, as a matter of fact, you wake up in your home. So if you want to do things outside of your home, you need to do something very specific: you need to leave your home. And if you have left your home, but want to do something in your home, you need to do something very specific: you need to enter your home.

      More generally, a monad takes a set of objects, and constructs a direct sum of types. The "monadic" or "container" types, on the left, and the inner type on the right. So for example, if we define:

      > data RightType = Red | Blue | Green
      > data LeftType right_type = One right_type | Two right_type

      the type LeftType RightType has values One Red, One Blue, One Green, Two Red, Two Blue, Two Green. That is, it is isomorphic (equivalent) to the type (Left, Right) where

      > type Right = RightType
      > data Left = One | Two

      Now, in parallel with the in the home/outside of the home example, if you want to do computations on the Right values of a LeftType RightType value, you need to "go to the right", using bind (>>=). Now, as it happens, the Haskell Monad typeclass implementation of bind makes it so any computation "on the right" returns a Monad instance. That is to say, you're automatically sent home after going to work. Still, if you want to do it by hand, you can use return. Indeed, every monad has an equivalent to these two functions, and it is rather the most important part. Because of these two functions, every monad is also a state machine (so stateful programming is straight forward).

      Plain old function application and definition is "monadic", since variables are bound in one context from another context (via pattern matching), and the "return value" is "returned" to the calling context. With these two insights, we can see why monads are sufficient to keep Haskell computations pure: they always occur on the right side of the IO value constructor. Impure computations occur "in" the IO data constructor (really, in the compiler and runtime). The bind function injects values taken from the environment into functions for use in pure computations.

      There is some pretty deep mathematics that connects this notion of a Monad to things like "queries" and "actions". In particular, every monad also has a "join" function defined (and can be defined in terms of return and bind). Every monad has an "eval" function that can be defined in terms of return and bind. The point of bringing these up is to mention that a monad implicitly defines semantics to evaluate the "syntax" (or shape) of a value. This also relates to pattern matching as I explained above. (The pattern matching algorithm acts to strip away unnecessary data constructors and bind variables) More generally, Monads represent unfoldings and refoldings of data.

      --
      After all, I am strangely colored.
    17. Re:Concurrency? by Anonymous Coward · · Score: 0

      The answer is basically a) though there is a technical argument as to why it's not actually breaking purity.

      Monads are not strictly a language feature, they are a concept that you can implement within the language (and there many instances scattered through various libraries). Because Haskell is pure, the monads you can implement are also pure, but they can simulate imperative features like mutable state (see the State monad).

      There is one monad called IO that cannot directly be implemented in the language. It is specified by the language report and provided as primitives. This lets you write pure programs that compose impure actions. The top level result of your program is then one of these compound actions and this action gets executed by the runtime system. (This is a slight simplification, in reality the evaluation of the construction of the action and the execution of the action are interleaved. It's also not as inefficient as it sounds, in fact there's essentially no overhead to it at all.)

    18. Re:Concurrency? by Frater+219 · · Score: 1

      A monad is not a specific data structure (like an array) or a language feature (like a loop or conditional). It is not something that is put together by the compiler (like a compiled function) and it is not magic, either.

      "Being a monad" is a mathematical property, like "being commutative" or "being symmetric". It has to do with values following a particular pattern, having operations defined on them that interact in a particular way. (These are called "monad laws", and they're the same sort of thing as the "identities" you get in high school algebra.)

      Any sort of thing that follows the monad laws is a monad. In Haskell, we say that any type that follows the monad laws can be made a member of typeclass Monad. Casually, we say that "lists are a monad" and "IO actions are a monad".

      What does it mean to be a monad? Roughly, it means that you can chain operations together. You can map a function over a list, or filter the list's elements to get a new list, or more generally "fold" a list by recursively applying an operation to collect a result. (Like the factorial function repeatedly applies multiplication.) Also you can join a list of lists together into a single big list.

      It turns out that monads can represent the idea of "sequence" quite well. Lists are, after all, a sort of sequence. But so are IO actions -- all those "non-functional" things a program has to do, like read a file from disk, or write its contents to the terminal. IO actions form a sequence in time: if you want to write the file's contents to the terminal, you have to read them from the disk first.

      The way that this works, under the hood, is to express the "later" actions as having the "earlier" actions' results as function arguments. Since a function's arguments have to be evaluated before the function can be applied, the disk gets read before the terminal-writing happens.

      So monads are not a loophole that lets you cheat and do non-functional things inside a functional language. Rather, they are a model that lets you describe IO actions as just another sort of functional value. The only bit of "magic" necessary is that the main function of a program has the IO type.

    19. Re:Concurrency? by TuringTest · · Score: 1

      I come from an imperative background myself. Let's see if my explanation of I/O and state handling in pure funtional languages, based on imperative metaphors, makes more sense for you. Please let me know if you find the following useful, I might expand it to my own personal "monad tutorial" (this seems to be a tradition when learning Haskell).

      - Monads are program structures that represent processes (and one particular kind of process for each kind of monad), but in a different way than functions represent processes. Actually I think of monads as little virtual machines embedded in the functional language, that encapsulate all the boring bookkeeping and boilerplate that must be done in any program alongside the interesting business logic.

      - A monad is used as a framework: you will program a sequence (or 'pipeline') of instructions in an imperative style (the do-block), using some vocabulary defined by the monad (the monadic type constructor, and return and bind operators). These blocks can then be instantiated and passed to the monad, to be executed according to the control logic programmed in the monad definition. Side effects during the sequence of actions in the do-block are instructions evaluated outside the do-block, but inside the (functional) monad code.

      - As for the I/O and state handling, remember that you have IO and State monads, and that each monad represent one kind of computation. IO represents *processes that interact with the real world*, and state monads represent *processes that depend on an internal state, that changes as the process evolves*. The trick to use them in a pure functional language is that the actual side-effect is not spread all over your programming language, it's encapsulated inside the monad definition.

      - The good thing of all this programming style is that you can actually *do* imperative programming, but in a much more controlled manner: instead of relying on the "generic VM" embedded in your imperative programming language (with all its risk of incorrect side-effects) you can execute it in your controled micro-VM defined by the monad. In that way, the only side-effects allowed inside the do-block are those that you enable yourself. Monads work as aspects in OOP: they represent one particular kind of unrelated logic (such as exceptions, concurrency...) that must be processed in the background of your main computation, and can alter its control flow. If you want your block to handle several aspects at once, you can always wrap several monads one inside another.

      As for your questions, as I see it:

      1) Haskell is pure functional, but that means "everything can be described as functions, even side-effects". Side effects happen inside do-blocks during the monad pipeline evaluation, but are side-effects only with respect to the do-block, not with respect to the language (the language views them as function calls over the monadic values).

      2) True. Thanks to monads, you can embed side-effects to the do-block inside the IO monad (whose low-level system calls are then defined as a language primitive embedded in the read/write functions, the same way as it's done in imperative languages with read/write subroutines). If you expand the syntactic sugar of the do-block it gets transformed into a series of function calls, in which the monad state is one input parameter and the new state is in the result. In order to understand how this works, I'm affraid you should also learn about continuations, which complement monads in order to describe imperative execution in terms of functions.

      For the last questions, we must get a bit philosophical here, in the sense that it depends on how you define "computation". It's been demostrated somewhere that imperative and functional programming are mathematically equivalent (i.e. both have the power of Turing machines). This means that you can represent functional languages using an imperative program, but also that you

      --
      Singularity: a belief in the "God" idea with the "demiurge" relation inverted.
    20. Re:Concurrency? by xZgf6xHx2uhoAj9D · · Score: 1

      I think an easier way to think of this is to think about how another functional language, Concurrent Clean, does side effects. It has an object "world" (and, with typing restrictions, ensures that you can only ever have one copy of "world"). If you want to do a side effect like write to a file, you need to give it (the only copy of) "world" and it will hand you back a changed "world" to reflect that it did something magical. I.e., all functions with side-effects require this passing of "world" around.

      Well that's not actually how Haskell does side effects, but it could be! A monad is abstractly a way of threading implicit information around. A monad by itself is purely functional: all it does is hide away implicit things like passing around data. Every monad except for one is totally transparent and you can see exactly what it's doing behind the scenes, because every monad except for one is side-effect-free.

      The IO monad is the only monad that has side effects and, not coincidentally, it's the only one that's opaque (you're not allowed to see how it's implemented). That's for a very good reason: since it does have side effects, it would be impossible to implement the IO monad in Haskell. But conceptually sometimes I like to think of it as secretly passing "world" around from function to function because conceptually it makes it simpler to understand.

    21. Re:Concurrency? by unbug · · Score: 1

      Here is a philosophical view of the whole thing. You can think of effectful computations as functions from a World to a World where a World contains everything that we consider mutable (including RAM, the disk, the internet and so on). For example, putStrLn takes a World and a string and produces a World which is exactly like the old one except that the string has been written to the standard output.

      Of course, the two Worlds - the one in which the string hasn't been output yet and the one in which it has - can't coexist. That is, once you actually output the string you can't go back to the old World. This means that if you apply putStrLn (or any other "World transformer") to a World you can't reference that World any longer, only the one that putStrLn gives you as its result. The programming language has to ensure that Worlds are accessed linearly - if you have a World and apply a function to it, you get a new World and can't reference the old one. If this is guaranteed, then World transformers like putStrLn can be evaluated simply by modifying the one and only real world. This doesn't make the language impure because the program can't detect that the old World has changed - it can't reference it.

      This kind of linearity can be implemented through linear types (which is what Clean does) or monads. In general, monads don't have anything to do with side effects. But there is one particular type of monad, called state transformer, which provides linear access to an encapsulated state. And there is one particular state transformer monad (called IO in Haskell) whose state is the World. The standard library defines primitive World functions (like putStrLn) based on this monad and programmers write their programs by composing these primitives in interesting ways. There is nothing deeply magic about it.

    22. Re:Concurrency? by Lemming+Mark · · Score: 1

      That's cool, I wasn't aware of that. Seems like it might be useful for scientific code. I know Fortran includes the ability to declare pure functions and (I think) verify their purity, which sounds useful.

      Though I imagine the problem for larger computations could be that you're limited to writing functional-style code, at which point you might be better off using a language designed for it? What optimizations does gcc actually do on pure functions, having identified them? I think it would be very interesting to tie this with something like Apple's Grand Central Dispatch (in an automated way, of course) to get computations parallelised magically to whatever degree the hardware can support.

    23. Re:Concurrency? by poopdeville · · Score: 1

      This is exactly how stateful programming works in Haskell. You create a monadic type of states S (that is, they each take one argument). For any given type A, you implicitly create the pair (S, A). (Really, it's the "pair" S A) Side effects are literally handled by "moving" the scope of computation left and right, with return and bind respectively.

      But conceptually sometimes I like to think of it as secretly passing "world" around from function to function because conceptually it makes it simpler to understand.

      This is the canonical interpretation. That, or its dual -- that a monad's bind function injects a value into the "right side" context, and that return "returns" a value from the right-side context to a context where you can modify the monadic value constructor (say, mapping it to another one). Both of these are equivalent.

      --
      After all, I am strangely colored.
    24. Re:Concurrency? by Anonymous Coward · · Score: 0

      That's what I really wasn't understanding: Haskell does let you create side effects. But it is still a "pure functional" language in the sense that the side effects are implemented in such a way that you can still analyze Haskell programs as pure functional programs, because the side effects that Haskell lets you create are entirely hidden from the universe that Haskell knows about.

      This isn't quite right. Haskell can model side effects, and the side effects do not have to be hidden from Haskell. This is typically done with monads, which are formally equivalent to state machines. Every monad has a function called "eval" which can be defined in terms of bind (>>=) and return. eval does what it says: it runs the state machine and returns a value.

      IO is a "special" monad because its eval function is written in C instead of in terms of its Haskell bind and return functions. It can inject state into pure code, as arguments to functions. If you were to re-write the IO eval function in terms of >>= and return, IO would merely simulate input and output. For example, if your program is supposed to write to a file, it would in fact be creating a representation of a file in memory and storing it there until the program terminated. Depending on where you gutted the eval function, you could theoretically have a representation as abstract as a "File" type value, or as concrete as a sequence of bytes as yet unwritten data in the binary ordering of your choice. You would be unable to write the file to disk without the special eval function.

      The IO monad's bind and return functions are pure. Indeed, the entire language is. The only construct that isn't is a function you can't call from within the language, because it calls your program.

      http://haskell.org/ghc/docs/latest/html/libraries/base/src/GHC-IOBase.html#IO

    25. Re:Concurrency? by Estanislao+Mart�nez · · Score: 1

      I'm still tempted to quibble at the difference between "opaque" and "side effect free". Hidden side effects are still side effects, although I guess so long as they truly are opaque then the formal constraints on the language are still enforceable, and one gets the power of pure functional programming out of it.

      We need a more careful definition of "pure" and "side effect" to answer this one.

      A pure function (or, mathematically speaking, just a function) is a value that maps each value of a domain to exactly one value of its codomain. The result of applying a pure function to a value depends on nothing other than the function and the value it applies to. If f is a pure function and a is a value, f(a) always has the same value, no matter in which context you call it.

      Correspondingly, an impure function (which is mathematically not a function at all) is one where the same function, applied to the same value, can produce different results at different times. This means that the result of the function is context dependent; the function result depends on its arguments and some piece of mutable context.

      Now, a side effect is any change to a mutable context. If a function has a side effect, then a call to that function has the potential to change the values returned by future calls to impure functions.

      So, Haskell is functionally pure because all functions you can write in Haskell are pure; the language doesn't allow you to write any code that implements an impure function where the result depends on anything more than the argument values. Because all of the possible Haskell functions are pure, they are all side-effect free relative to each other. No Haskell function can have a side effect visible to any other Haskell function; this follows just from the fact that they are pure.

      However, the trick that the IO monad does is that your program is implemented as a pure function from an initial state of the world to a final state of the world. The runtime system, conceptually speaking, calls this pure function, but it never calls it with the same initial value, and the program's main function likewise never returns the same value. So the IO functions in your program are pure (in a mildly perverse sense, given that the IO values are never reused) and side-effect free (as far as any of them can detect), even though the runtime system is side-effecting the world behind the scenes.

      Why does it matter to insist that the language is pure and side-effect free? Because it means that you can reason about code and transform it in ways that you couldn't if the language wasn't. In particular, you have the following guarantees:

      • The same function applied to the same values always has the same result, period.
      • You can compute the values of function applications in any order that respects the dependencies between values, and you will always get the same result.
      • If you compute the value of a function application in one part of the program, you can always reuse the result there if you need to compute the same function application anywhere else.

      These guarantees don't apply in impure functional languages like ML, because those languages allow for pure functions that side-effect the world; e.g., a function print_hello in ML may print a string "Hello" and return "unit," the ML/Haskell equivalent of null. The function is pure, and doesn't cause other functions to be impure, but you can't reorder the call to print_hello with another one, because that other one might then perform IO in the wrong order. You can't decide to cache the result of print_hello either, because then you'd fail to print the string when the program was supposed to. Haskell is designed in such a way that the guarantees listed above hold everywhere, but without breaking the IO system.

    26. Re:Concurrency? by Abcd1234 · · Score: 1

      a) Haskell is not actually purely functional: it is a purely functional core sub-language with extremely well controlled additional side-effect-producing parts

      b) Monads are not actually considered "part" of the Haskell language, in the same way that pre-standardization STL was not "part" of the C++ language.

      c) I'm completely missing something.

      It's sort've a combination of b and c.

      Think of a Monad as a general way of modeling some sort of computation. There are many kinds of computation that can be, and one of them is a computation that makes use of side-effects. In such a computation, the "world" state is threaded through the computation, so when you, say, read from a file, you end up with a function that takes the "world", a file handle, and returns a new "world", and a string. But all that detail is hidden from you by the IO monad, which takes care of handling that state threading for you.

      But the important thing, here, is that the concept of a Monad is completely general. But even more surprising, a Monad, which models stateful computation, can be implemented in pure Haskell. And so IO, ST, and others, are really just libraries on top of Haskell which allow one to perform stateful computation within the context of a pure language. It is important to note, though, that, in general, non-monadic code can't call monadic code. So, for example, a pure function can't go and call an IO monad directly. In this way, the impure code is isolated away from the pure code, thus allowing the programmer to apply state where it's appropriate, but to ensure it's kept in it's own little box where it can't hurt anyone else.

      Now, the consequence of this is that, conceptually, Haskell programs are inevitably built with a shell of code running with an IO Monad, and a functional core which implements the interesting bits of the program. You can, of course, write an entire application within an IO Monad, but that sort've defeats the purpose of using a pure language like Haskell.

    27. Re:Concurrency? by mandolin · · Score: 1

      Though I imagine the problem for larger computations could be that you're limited to writing functional-style code, at which point you might be better off using a language designed for it?

      Point taken, assuming it has to be fast and there is that much critical code.

      What optimizations does gcc actually do on pure functions, having identified them?

      Well, it doesn't dispatch them :-) from what I read in the documents, all it might do now is common subexpression elimination.

  7. Oh, be still my heart.... by gestalt_n_pepper · · Score: 2, Funny

    Haskell! Haskell! Every geek's favorite mental masturbation toy!

    --
    Please do not read this sig. Thank you.
    1. Re:Oh, be still my heart.... by Red+Flayer · · Score: 0

      Haskell! Haskell! Every geek's favorite mental masturbation toy!

      Speak for yourself. My favorite mental masturbation toy is slashdot. Where else can I get my mental rocks off by emulating Yakov?

      In Soviet Russia, Haskell masturbates to you!

      --
      "Trolls they were, but filled with the evil will of their master: a fell race..." -- J.R.R. Tolkien on Olog-hai
    2. Re:Oh, be still my heart.... by Anonymous Coward · · Score: 0

      Masturbation can be fun.

    3. Re:Oh, be still my heart.... by Anonymous Coward · · Score: 0

      Is that you, bonch?

  8. meh by AlgorithMan · · Score: 1

    Haskell can't compete with my implementation of the pure lambda calculus!
    screw all that syntactic sugar, lambda expressions ftw!

    --
    The MAFIAA is a bunch of mindless jerks who will be the first up against the wall when the revolution comes
  9. NoNPlusKPatterns by harry666t · · Score: 1

    NoNPlusKPatterns... Seems that they're finally banned.

    http://www.mail-archive.com/haskell@haskell.org/msg01261.html

  10. on haskell quicksort by j1m+5n0w · · Score: 1

    I agree it's not always the best example, but there are four reasons why "qsort [1..10000]" is slow, and you can address three of them without writing something that's "100 times less readable than C".

    The first problem is that naive quicksort on an already-sorted list/array is O(N^2). The fix is to grab an element out of the middle and use that as your pivot. That alone will make qsort far faster. (I tried it.*) The resulting code is, of course, a bit messier.

    Secondly, the qsort function has no type signature, so it will default to the most polymorphic implementation, which is something like qsort :: Num a -> [a] -> [a]. Typing "qsort [1..10000] probably (though I'm not sure, it's a ghci-specific thing) defaults to using Integer, which is less efficient than a machine Int. If you constrain the type signature the code will be faster.

    Thirdly, you're using ghci. Code compiled with "ghc -O2" is far faster. (Be sure not forget that -O2, it make the code about 10x faster.)

    The fourth reason is that C is doing in-place array swaps. (You can do the same thing in Haskell using the ST monad if you really want to. I don't think the result will be "100 times less readable", but it will be fairly ugly compared to the pure version. There are a couple such implementation here.) Whether doing quicksort with lists is good enough really depends on what you're doing.

    * Quicksort modified with a swap, then mangled by slashdot:

    module Qsort where qsort [] = [] qsort xs = let n = length xs in if n > 100 then let split = n `div` 2 (a,b) = splitAt split xs in _qsort $ (xs!!split) : (a ++ (tail b)) else _qsort xs _qsort [] = [] _qsort (x:xs) = qsort (filter (= x) xs)

    1. Re:on haskell quicksort by Pseudonym · · Score: 1

      Right, quicksort is almost always the wrong answer if you're sorting linked lists, as you are here.

      But consider a more complex algorithm, such as bottom-up polyphase merge sort. (WARNING: Untested code follows.)


      sort = mergePhase . generateRuns

      generateRuns [] = []
      generateRuns (x:xs) = split xs x x (x:)
              where
                      split [] _ _ _ k = k []
                      split (x:xs) minx maxx k
                          | x >= maxx = split xs minx x (k . (x:))
                          | x < minx = split xs x maxx ((x:) . k)
                          | otherwise = k [] : split xs x x (x:)

      mergePhase [] = []
      mergePhase [xs] = xs
      mergePhase xss = mergePhase (mergePass xss)
              where
                      mergePass (xs1 : xs2 : xss) = merge xs1 xs2 : mergePass xss
                      mergePass xss = xss

      merge [] ys = ys
      merge xs [] = xs
      merge (x:xs) (y:ys)
              | x <= y = x : merge xs (y:ys)
              | otherwise = y : merge (x:xs) ys

      It's a bit longer, but it's surprisingly fast and robust considering how little code is here. Especially interesting is the way that lazy evaluation works here; what looks like multiple passes are interleaved to preserve locality in a way that would require a lot more code in a conventional language. Also note the use of difference lists in the run generation phase; many languages would require extra reference/pointer hackery to achieve this.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
    2. Re:on haskell quicksort by j1m+5n0w · · Score: 1

      Data.List.sort uses mergesort (and the implementation is actually a bit shorter than your code, though yours seems a bit more readable to me). http://www.haskell.org/ghc/docs/latest/html/libraries/base/src/Data-List.html#sort

    3. Re:on haskell quicksort by harry666t · · Score: 1

      Thank you for your explainations. I wasn't aware that the example I've used was the worst case. I think I'd better go educate myself a little more on algorithms and data structures :D

    4. Re:on haskell quicksort by Goaway · · Score: 1

      The fourth reason is that C is doing in-place array swaps.

      And the ability to do that is the whole reason for quicksort. If you do quicksort without doing it in-place, you're just being silly.

    5. Re:on haskell quicksort by j1m+5n0w · · Score: 1

      Quicksort with in place arrays is O(nlogn). Quicksort with lists is O(nlogn). The difference between the two is a constant factor. Not everyone cares enough about constant factor speed increases that they would abandon a programming language because of it, but some do which was the point I was trying to make.

      Using lists just means that quicksort isn't any better than any of the other nlogn sorts, but it's still one of the easiest efficient sorting methods to explain. Mergesort is usually preferred in functional programming circles because it's about equally complicated but you don't have to worry about bad performance in the already-sorted case.

    6. Re:on haskell quicksort by Goaway · · Score: 1

      Not everyone cares enough about constant factor speed increases that they would abandon a programming language because of it

      First, it's a constant factor in speed, but not in size. Second, nobody said anybody was abandoning any languages because of it, only that you shouldn't go around showing it off as a "quicksort".

    7. Re:on haskell quicksort by Pseudonym · · Score: 1

      It is shorter, but it doesn't make any attempt to run in linear time on already sorted lists, which is something that most industrial strength sort algorithms do.

      I make no claims that my code is industrial strength (I didn't even check to see if it compiles), but it's a better approach than HBC's library code took in 2002.

      --
      sub f{($f)=@_;print"$f(q{$f});";}f(q{sub f{($f)=@_;print"$f(q{$f});";}f});
  11. Closures are probably really necessary. by Estanislao+Mart�nez · · Score: 1

    Closures are a mechanism that allows you to efficiently write a function that can produce infinitely many different functions as its output. Functional programming without closures would either be a big pain, or would involve compiling new functions at runtime all the time. There might even be things that you provably can't do without closures; in the lambda calculus, beta-substitution can substitute free variables inside a lambda abstraction with values from outside its scope, so it comes down to whether certain restrictions on substitution impair Turing completeness.

    And once you have closures, you need garbage collection.

    1. Re:Closures are probably really necessary. by Cassini2 · · Score: 1, Interesting

      And once you have closures, you need garbage collection.

      You may have explained why Haskell will never work for certain HPC applications. Essentially, for really high-speed CPU performance, static variables are essential. A static variable has the nice property of being at an immutable memory location, which enables all sorts of optimizations. Additionally, once it is shown that a memory location is fixed, and not accessed by another function, then important additional optimizations are allowed, including optimizing out instructions involving constants.

      Modern compilers can only optimize x = a + b * y when a and b are simple constants (often 1 or 0), and x, and y are simple variables (like double precision multiplies). If x and y are arrays, or classes, modern compilers won't unroll the loops because it could take a very large amount of time to complete the compile. However, if the loops were unrolled, then the resulting program would execute much quicker.

      This subtlety is very important in real-time control systems, where speed is paramount. The mathematicians generate an "optimized" control equation by writing y = A B C x D E, where A, B, C, D, and E are matrices, and x and y are vectors. The PC based simulators are very slow in computing y, because of all the large matrix multiplications. However, if you expand the equation out into the individual multiplies, it turns out the compiler can make huge simplifications, which is why the math people do all of those matrix multiplies. These simplifications only happens when one expresses the actual multiplication and additions to the C compiler as simple statements, like double precision multiplies of static, constant, and function local variables. The C compiler doesn't know how to optimize loop matrix multiplies.

      These optimizations only work if key loops in the program are unrolled at compile time. If the language is so complex, that the compiler cannot even eliminate all dynamic memory allocations, then it is impossible to unroll key loops. A limited language like FORTRAN with MPC/HPC extensions can become very fast relative to Haskell, as the compiler has much more freedom to do optimizations.

      Simply put: a compiler designed for a limited problem set (FORTRAN) can be much faster than a fully general programming language for any possible program (Haskell).

    2. Re:Closures are probably really necessary. by Abcd1234 · · Score: 1

      Additionally, once it is shown that a memory location is fixed, and not accessed by another function, then important additional optimizations are allowed, including optimizing out instructions involving constants.

      Funny you would use that statement to demonstrate how Haskell isn't good for HPC, considering that a pure functional language *has no mutable variables*, which theoretically enables a whole new class of optimizations.

      As for the rest, TBH, I'm not sure what your point is. Haskell isn't dynamically typed, so nothing stops you from writing a highly optimized, unrolled version of, say, a matrix multiply if the matrix contains Integers (or whichever primitive type you prefer).

      TBH, I think the real reason you won't see Haskell used in HPC applications any time soon is laziness. It's just too difficult for programmers to reason about performance in the face of laziness (despite the potential performance wins it could, in theory, provide).

    3. Re:Closures are probably really necessary. by Abcd1234 · · Score: 1

      And once you have closures, you need garbage collection.

      You might want to tell that to Apple...

  12. Gee by Anonymous Coward · · Score: 0

    How many languages does it take to tell Mrs. Cleaver how lovely she looks today?

  13. Ward, don't be too hard on the Beaver by unitron · · Score: 1

    The revision to which I look forward is the hack that causes it to make very impolite comments to Mrs. Cleaver.

    --

    I see even classic Slashdot is now pretty much unusable on dial up anymore.

  14. A simple explanation by Estanislao+Mart�nez · · Score: 1

    A purely functional language can model a stateful computation by encoding the program as a sequence of state transformers. Basically, the state of a computation is explicitly represented in the program by actual values that you pass around as arguments to functions that return a new states. By chaining state transformer functions you can write an equivalent to any imperative program.

    Thus, in principle, could encapsulate IO into a purely functional language simply by requiring that all IO functions take an abstract "state of the world" argument and return an altered "state of the world" value. These "state of the world" values don't have any functions that allow you to introspect into them; all they serve to do is to determine the order in which IO actions would be performed.

    So for example, your purely functional language could have a print(str, sow) function would take as its arguments (a) a string to be printed, and (b) the state of the world before the string has been printed, and return (c) the state of the world after the string has been printed. If you want to print "Hello " before "world!", then you have to write code like this ("sow" means "state of the world," and is passed in as the argument to the main() function of the program):

    function main(sow):
    print("world!", print ("Hello ", sow))

    In this pseudocode, "Hello " is printed before "world!" because the state of the world that results from the inner print() function call is passed in as an argument to the outer one.

    The problem now is that unless you do something to forbid it, people can write impossible programs by using nonsensical state chains; e.g., by trying to use the same "state of the world" value twice as if you could reset the world to the state before you printed "Hello " and reperform this destructive action:

    function main(sow):
    let s1 = print("boo!", sow)
    in discard_first(print("world!", print ("Hello ", sow)), s1)

    function discard_first(a, b):
    b

    In this nonsense program, you're supposed to print both "boo!" and "Hello " as the very first thing, which is impossible. The main() function is also supposed to return the state after "boo!" was printed, which means that the caller of main() is allowed to print stuff before "world!". Yeah, it makes little sense.

    Basically, you can think of monads as an abstraction that allows us to implement this kind of purely functional state-passing program, but encapsulating the state-of-the-world values so that the callers can't touch them, and thus prevent them from writing nonsensical programs. So strictly speaking, they allow the language to provide side-effecting operations but isolate them from the purely functional parts of the language. Any function that does IO must use the IO monad in its type, and purely functional code that can't extract any values or state from the IO monad. To perform any computation on values that depend from things you read from IO, for example, you can't pull out the state-dependent values out of the monadic context and pass them as arguments to your functions; you must, in effect, pass your functions to the IO monad so that its internal implementation can apply them to the quarantined, stateful values.

  15. Why isn't FP more popular? by j1m+5n0w · · Score: 1

    Then why aren't the FP shops kicking as and taking names?

    There are several reasons. As abigor stated, functional programming is not well understood by the majority of programmers. If you suppose that there is one Haskell programmer for every 1000 Java programmers, then that one Haskell programmer has to be one thousand times more productive in order to get noticed by the larger programming community. (I don't know if the distribution is that skewed, but I think you get the idea.) There are small companies that have been very successful at using FP, but they're easy to miss if you don't look in the right places.

    Another reason is that the fastest functional languages are still slower than C in general. I don't think the difference is as much as you say, Haskell and Ocaml both have very good code generators. Do check out the "programming language shootout" results. (Be sure to use -O2 with ghc, though, or you really will see a 10x difference.) However, there are many programmers for whom if you give them a choice between one language and another, they will always choose the faster language regardless of other considerations. A lot of supercomputing people still use Fortran, for example.

    A third reason is that software firms are very risk averse. If you have a problem that you know a team of average Java, C++, or C# programmers can solve in N months, versus a smaller team of more expensive functional programmers who may or may not be able to solve the problem in much less time in an unknown language that no one else seems to be willing to bet the farm on, then a lot of firms will see FP as an unacceptable risk.

    Fourth, consider the sales pitch for Haskell: "Hey, check out this cool new language! It's a bit slower than C, and you can't change the value of any of the variables. It was designed by committee. Half of the people who use it got their PhD by hacking a type system extension onto ghc." The primary benefits of Haskell are hard to describe to people who haven't used it, namely that programs tend to have fewer bugs (thanks to the strict type checker), and it often takes much less code to solve a given problem. The drawbacks, however, are rather obvious up-front: how many programmers do you know who would welcome the idea of "everything is const"? There aren't really any Haskell programs that you couldn't write in C, or Java, or C++, or C#, or Python or any of dozens of other languages. The difference is, how much code are you going to write, and how much work is it going to take to make the program reliable?

    1. Re:Why isn't FP more popular? by Vintermann · · Score: 1

      "Another reason is that the fastest functional languages are still slower than C in general."

      No, this isn't a reason. Open source software on Unix-clones is about the only place C is still a general purpose language. Ocaml and Haskell are eminently competitive with Java and C# (and with C too, in these domains).

      --
      xkcd is not in the sudoers file. This incident will be reported.
  16. Lua by j1m+5n0w · · Score: 1

    I would consider Lua a functional language (and I think it's designers went out of their way to make it so), though it isn't exclusively functional; it is possible (and typical) to write imperative, stateful code in Lua as well. I haven't used it much, though, so it may be that there is some drawback to using a functional style that I haven't considered.

  17. purity, side-effects, and monads explained by j1m+5n0w · · Score: 4, Interesting

    Let's see if I can explain this simply.

    The Haskell language, like any other language, needed constructs like "read" and "write", but to implement them as simple functions would have broken the underlying assumptions of purity and lazy evaluation.

    Haskell happened to have monads. A monad is essentially a typeclass for containers, that allow you to do certain things to combine containers of the same type, without having to worry about what kind of container it is. Most (all?) of the containers in the standard library are instances of Monad.

    The Haskell language designers came up with (or perhaps borrowed) an idea. They would create a new container type, called IO, and make it an instance of Monad. However, unlike other containers, it would not have any accessor functions. You can pass around an object around of type IO in pure code all you want, but you can't ever examine the contents of the IO container from within "pure" code. The only thing you can do with it is combine it with other IO objects. Combining two IO objects is equivalent to evaluating the file operation or what have you inside one IO object and passing it's result to and executing whatever is inside the second IO object. The actions within an IO object, however, are free to invoke pure code if they like.

    Every haskell program has a main() function, which is an IO action. This allows you do do any necessary file IO your program needs to do, and it can also call out to pure functions. Pure function cannot invoke IO actions. Most Haskell programmers try to keep the IO actions as simple as possible and rely on pure code for the bulk of the program.

    As a concrete example, I wrote a ray tracer, which parsed a text file and generated an image. As I was writing it, I got to the part where I needed to write the file parser. I thought "oh, no, this whole thing has to execute within the IO monad and it'll be a big mess". However, it was not so. After scratching my head a bit, I ended up writing a pure function that takes a simple text string and converts it to my internal representation of a scene, ready to be ray traced. Within main (within the IO monad), I would read the text file in with a lazy function "hGetContents", which returns a string which is the contents of the file. I would pass that string to the parser, and then trace a grid of rays (one per pixel) against the parsed scene. The list of pixels with their calculated color values was returned to the IO monad, where I used OpenGL to plot them to the screen.

    The interesting bit about this is that hGetContents is lazy. In a strict (i.e. non-lazy) implementation, the whole string would be read at once. This is inefficient, and may cause problems for text files that won't fit in memory. Due to laziness, however, the string is passed into the parser without being fully evaluated. As the parser needs more data, the run-time system will cause hGetContents to read another block. So, here we have an example of a pure function that's indirectly triggering IO, and it's doing it all without violating the constraints of the type system.

    1. Re:purity, side-effects, and monads explained by Anonymous Coward · · Score: 0

      So what you're saying is that using Haskell allowed you to side-step the problem of having to think how to implement concurrency, and instead allow you to focus on the really difficult parts of the program like how to implement I/O.

      This is the absurd point the "pure" functional programmers always forget to mention. The whole purpose of most REAL programs is to have side effects. To claim your language side-steps the problem of side-effects by eliminating them effectively means you've side-stepped the problem by limiting yourself only to writing programs that can't actually do a wide range of real tasks in a sensible fashion.

  18. Re:Monads (was Concurrency?) by speaker4thedead · · Score: 1

    I think that experienced haskellers often forget to explain that there is a portion of the program that is not strictly functional. The thing is that the programmer is not given access to it. Instead, the programmer is asked to pass around descriptions of the I/O actions to be taken. A monad is a data type that (amongst a vast number of other things) can be used to structure these descriptions so that we can get the order of execution right. (notice that I didn't say 'evaluation')

    The next part is a bit sloppy because monads turn out to be even more abstract than described, but it suffices to explain the concepts that give us the ability to be pure and still interact with the outside world.

    Every Haskell program is an instance of a function that returns an IO Monad. "Inside" that monad (for the moment, think of it as a box plus a little bit of extra data) is a description of the I/O action to be performed and a new function that takes the result of that I/O (possibly discarding it) and produces another monad. Only the function inside the monad is allowed to refer to the result of performing the execution of that monad, but it is also able to refer to any functions outside of the monad. (Like lexical scoping.)

    There's always a impure portion to a program that the programmer never gets to see. It's job is to evaluate just enough of a function to get ahold of an I/O monad, read the description inside that monad, perform the action and then repeat the whole process again by passing the result into the function if found inside the monad. This division of duties is enforced by only allowing the programmer to use the functions with stuff a description and function into a monad, but not the ones to get it out. Only the impure part of the function can

    All this so far is interesting, but it seems like it would take an awful lot of discipline just for the sake of purity. However, what really make monads snazzy is that there are some great tricks with syntactic sugar that can help the programmer design these descriptions in much the same way he would write an imperative program. This is Haskell's 'do' syntax. The 'do' syntax doesn't make a purely function Haskell program imperative, but it sure makes it look a lot like it is.

    Still, monads are nothing more than a data type with a couple of particular kinds of functions defined on it. In the case of I/O, those functions stuff things into the monad, combine monads and get information out of the monad. If you use monads for other things, it might be worthwhile to think of those functions as serving other purposes. Haskell's monad type class simply abstracts the features of all these so that algorithms used on one can often be used on all the others... even if it does obscure the original interpretation of what's going on.

    --
    "My religion is to live --and die-- without regret." -- Milarepa
  19. Definition of purely functional by Anonymous Coward · · Score: 0

    The definition of purely functional is a bit more complicated than you think it is, but Haskell is pure. A Monad is just a mathematical structure and is no more a part of the language than groups, rings or fields are - you can still put them in your program though. The IO monad is a bit special, because it's depending on the real world, but it's still a monad. The programming verification you speak of is much easier than the corresponding things you can do in C, since you know that there will not be any null pointer dereferences and similar horror stories in your Haskell programs you can focus on verifying the interesting things.

  20. Haskell and side effects (was Re:Concurrency?) by StarFire_FIN · · Score: 1

    Haskell does have side effects, just like any other useful programming language. However, you can't put side effects just anywhere in a Haskell program; you have to explicitly specify which functions have side effects.

    This is done using the type system so that the return values of all functions that can have side effects must be IO x (ie. IO<x> in C++/Java notation). This way, you (and the compiler) can be sure that any function that DOESN'T have the type IO x is 100% side effect free, allowing easy parallelization, many types of optimizations, etc. In other words, all side effects are put in a separate "side effect bin".

    Another big thing to understand is that Haskell makes it impossible (well, not really, but strongly discouraged) to return a value from IO back to the pure part of the program. Any computation that may depend on the result of some side effect is considered to have side effects of its own; removing a value from the "side effect bin" is a side effect. Essentially, side effect code can call both side effect code and pure code, but pure code can only call other pure code.

    Since every useful program has at least some side effects (reading input, returning output), every Haskell program has a main function which has the type IO () (ie. has side effects, doesn't return anything). The main function can then call the rest of the program, just like in other programming languages.

    In order to keep this type of programming from being a total pain in the ass to program with, Haskell uses monads (which are an unrelated concept, they are used for lots of other things as well) to make it easy to compose smaller IO functions into larger, more higher-level IO functions.

  21. But to what end? by jonaskoelker · · Score: 1

    things can be passed from one function to another without naming them.

    Isn't that a rather point-less feature? ;-)

  22. Haskell cannot do in-place qsort by master_p · · Score: 1

    Can it; I think not. It's incredibly cool to write qsort in just 2 lines of code, but it's incredibly slow.

    1. Re:Haskell cannot do in-place qsort by Anonymous Coward · · Score: 0

      It can, but you have to use arrays and ST.

    2. Re:Haskell cannot do in-place qsort by j1m+5n0w · · Score: 1

      Rather than type what I wrote in a similar thread again, I'll just link to it here.

      Summary: qsort [1..10000] is slow not so much because it isn't an in-place sort, but because naive quicksort on an already-sorted list is O(N^2) rather than O(NlogN). If you use an element from the middle of the list as the pivot instead of the first element, it performs much better.

      As the other reply already stated, you can do in-place quicksort in Haskell by using the ST monad, if that's really what you want.

    3. Re:Haskell cannot do in-place qsort by Abcd1234 · · Score: 1

      Of course it can, why not? Haskell *does* allow modeling stateful computations, you just have to encapsulate it in a Monad. So break out an ST Monad, do your in-place sort using an array, and voila, you're done.

  23. hGetContents is only *technically* typesafe by Captain+Tripps · · Score: 2, Informative

    As the parser needs more data, the run-time system will cause hGetContents to read another block. So, here we have an example of a pure function that's indirectly triggering IO, and it's doing it all without violating the constraints of the type system.

    Actually hGetContents cheats by using unsafeInterleaveIO. It's a cool hack, but lazy IO is an inherently risk business. For instance, if your program later wrote back changes to your scene file, the result is undefined. There's no guarantee of when the program is done reading the file. If you keep this in mind it's no problem, but if all IO worked this way you'd go insane. (Also consider the problem of error handling if there's a disk error.)

    1. Re:hGetContents is only *technically* typesafe by j1m+5n0w · · Score: 1

      Fair enough. I have learned, through experience, that one must make sure that the result of the computation based on hGetContents is fully evaluated before closing the file.