4

I've been using CoffeeScript for a while now. On Wikipedia, it is said that CoffeeScript is influenced by Haskell. But after I check out the syntax of Haskell, I have found little resemblance from CoffeeScript.

Which aspect of CoffeeScript is influenced by Haskell?

7
  • 2
    On the Wikipedia page itself it says "In CoffeeScript, the function keyword is replaced by the -> symbol, and indentation is used instead of curly braces, as in Python and Haskell." Maybe that's it.
    – Thilo
    Mar 14, 2012 at 2:02
  • 4
    Voted to move to Programmers Mar 14, 2012 at 2:16
  • 4
    @DeadMG: I don't think the syntax is the "most irrelevant" (otherwise Scheme wouldn't be less popular than Python :P), but it isn't the most important either. Mar 14, 2012 at 2:43
  • 8
    Notice the [1] next to the sentence you're referring to? That's a link to the first of the references of the article, a podcast interview with Jeremy Ashkenas, the designer of CoffeeScript. Listen to the podcast, and your question will be answered...
    – yannis
    Mar 14, 2012 at 2:44
  • 8
    @DeadMG From a computer's perspective, yes, but not to humans! Failure to understand this is why we have XML.
    – Pubby
    Mar 14, 2012 at 7:10

4 Answers 4

11

Coffeescript is a gateway drug for Haskell. Let's take a look at the Quicksort algorithm, as presented in Chapter Five of Learn You A Haskell For Great Good:

quicksort [] = []
quicksort (x:xs) =
       let smallerOrEqual = [a | a <- xs, a <= x]
           larger = [a | a <- xs, a > x]
       in quicksort smallerOrEqual ++ [x] ++ quicksort larger

And the equivalent in Coffeescript:

quicksort = (x) ->
    return [] if x.length == 0
    h = x.pop()
    smallerOrEqual = (a for a in x when a <= h)
    larger = (a for a in x when a > h)
    (quicksort smallerOrEqual).concat([h]).concat(quicksort larger)

The only obvious difference between these two bits of code is that the pattern had to be turned into a guard condition.

These are not equivalent pieces of code. The Haskell code will only do the list comprehensions lazily, i.e. when needed by the in line. Pattern recognition is a big deal in Haskell. Haskell will optimize this code with tail-recursion, whereas Coffeescript will just build a framestack as big as the number of recursions needed. And the Haskell version cares about the contents of the list and demands they be all of the same type, since Haskell is so strongly typed.

But one could be fooled, by their clear syntactical resemblence, into believing they were equivalent. And to some extent, a smart developer could use that resemblence to write Coffeescript that, if not lazy or strongly typed, was nonetheless better disciplined and more functional. Haskell is an excellent language for learning that discipline, and those skills are directly translatable to Coffeescript's syntax.

[EDIT] Building on Linus's excellent addition below, we can even simulate Haskell laziness:

quicksort = ([x, xs...]) ->
    return [] unless x?
    smallerOrEqual = -> (a for a in xs when a <= x)
    larger = -> (a for a in xs when a > x)
    (quicksort smallerOrEqual()).concat(x).concat(quicksort larger())

Now the two expressions only trigger when their results are needed, not just imperatively. I doubt this actually wins you anything, but it does seem to be getting closer to some Haskellian purity.

1
  • Update: Tail-recursion is now possible in ES2015 aka ES6. Fantastic. Now I don't need to learn Haskell and I get a great, exciting tool in my toolbox. I think everyone would do well to study the transpiled JS side-by-side with Coffeescript to learn to understand its applications and when to use it. Nov 29, 2015 at 22:15
4

Building on Elf Sternberg's answer, you can actually make quicksort even a little more "Haskell-like" with Coffeescript's destructuring:

quicksort = ([x, xs...]) ->
  return [] unless x?
  smallerOrEqual = (a for a in xs when a <= x)
  larger = (a for a in xs when a > x)
  (quicksort smallerOrEqual).concat(x).concat(quicksort larger)

It's not quite pattern matching, but it's a little closer. ;-)

1
  • 2
    I've used destructuring for objects (as hashes, for example), but haven't seen its use with arrays. Wow, that's very nice. I've learned something new. Thanks! Mar 16, 2012 at 16:28
0

For me, CoffeeScript sometimes looks really similar to Erlang.

For example:

CoffeeScript:

f_qsort([]) -> []
f_qsort([Pivot, Rest...]) ->
  [
    f_qsort((X for X in Rest when X < Pivot))..., 
    Pivot, 
    f_qsort((Y for Y in Rest when Y >= Pivot))...
  ]

Erlang:

qsort([]) -> [];
qsort([Pivot|Rest]) ->
  qsort([ X || X <- Rest, X < Pivot]) 
  ++ [Pivot] ++ 
  qsort([ Y || Y <- Rest, Y >= Pivot]).

There is a library which provides a way to write Erlang-like constructions right in CoffeeScript without precompilation, just wrap up it in special function. You can find it here: https://github.com/nogizhopaboroda/f_context.

-4

For me, the main difference is in function calls. In CoffeScript:

fun(bar(a, b, c))

or:

fun bar a, b, c

In Haskell:

fun $ bar a b c

or:

fun . bar $ a b c

Why oh why those commas between arguments.

Also the difference between quicksort (x:xs) = and quicksort = ([x, xs...]) -> is obvious, and confusing, because -> means something else in Haskell.

1
  • 1
    Question asks how CoffeeScript is influenced by Haskell, not syntactic differences
    – Alex
    Dec 9, 2014 at 12:02

Not the answer you're looking for? Browse other questions tagged or ask your own question.