Hacker News new | ask | show | jobs
by tome 3119 days ago
Let's elaborate on "curried" since that was what OP was interested in. How are functions in Haskell "curried" by default? Sure, you can write

    f x y = 2 * x + y
and that will define a function that takes an Int, say, returns a function. But why is that any more "default" than

    g (x, y) = 2 * x + y

?
2 comments

All functions in Haskell are single-argument functions. Multiple arguments are syntactic sugar. The syntax sugar can make it confusing to talk about but if you define an `add` function that takes two arguments x and y:

    add x y = x + y
it's sugar for multiple single-argument functions.

    add = \x -> \y -> x + y
When examining it this way, the `g` function above would translate to

    g = \(x, y) -> 2 * x + y
Which is a function taking a single tuple argument. It is still "default curried" but the argument being passed in is a single argument rather than multiple so we don't expand it to multiple single-arg functions. Perhaps it is more illustrative to show the definition as the single argument it is rather than using haskell's destructuring to pull x and y out of the tuple.

    g tuple = 2 * (fst tuple) + (snd tuple)
and a ghci session for completeness:

    Prelude> let g (x, y) = 2 * x + y
    Prelude> g (1,2)
    4
    Prelude> let y tuple = 2 * (fst tuple) + (snd tuple)
    Prelude> y (1,2)
    4
So when we say that Haskell functions are "curried by default", what we're referring to is roughly the underlying single-argument nature of haskell functions.
Those are different functions. Your `g` function takes a single argument, but it's a composite datatype. It's akin to the following Javascript:

    function g(args) {
      return 2 * args[0] + args[1];
    }
You're right that we could write either `f` or `g`, but the reason `f` is the "default" way is that it involves no extra datatypes. Consider the following:

    h [x, y] = 2 * x + y
I wouldn't say this is "default behaviour" in the same way as `f` or `g`, but it certainly seems 'closer' to `g`. Similarly:

    data Pair a b = MkPair a b
    i (MkPair x y) = 2 * x + y
This seems very "non-default", especially since it's using a non-default datatype. Yet that datatype is alpha-equivalent to `(x, y)`.

Whilst tuples (or the above `Pair`) are isomorphic to curried functions (e.g. via the `uncurry` function and its inverse), they're not alpha-equivalent, so there is a meaningful distinction between tuples and curried functions. Since tuples are defined in the Prelude, we could do away with them (and use `MkPair` instead, if we wanted), so they're not really "built in". On the other hand, functions are (AFAIK) built quite strongly into the core of Haskell, and hence we cannot avoid them, making them, and hence the function-returning behaviour of currying, more pervasive, unavoidable and hence "default".

(Note that Haskell may at some point be less tied to functions; e.g. Conal Elliot's 'compiling to categories', among others, looks like a reasonable justification for allowing something like an "OverloadedFunctions" pragma)