Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> A big gotcha for me was understanding the -> syntax. How can a function that accepts two arguments possibly have a type annotation like this?

    connectWords : String -> String -> String
This is one of the most maddening things for me about Haskell-like languages. I can never remember if -> is left or right associative. I mean there is only one way that makes sense:

    # String -> (String -> String)
But it could also be

    # (String -> String) -> String
Of course you get used to it after a while, but a nagging feeling remains. I would really prefer a bit of syntactic sugar.


If you consider the case of currying and the fact that Haskell functions can be partially applied by just not providing all of the parameters, it becomes clear that only the first version you wrote is correct. It is a single-parameter function with a return type of another single-parameter function.


I think when these type annotations are used, at least traditionally in e.g. Haskell, the functions are curried by default. In other words, all functions only take one argument. If all functions only take one argument, then it has to be the first interpretation, not the second.


Doesn't String -> String -> String mean it takes two arguments in this case though?

> The type annotation for connectWords is telling us that connectWords is a function that accepts two strings and returns a string.

Or maybe I misunderstand this whole thing. I know nothing about Haskell/Elm.


Thanks to ncd for clarifying, here are my own comments too. When you write

    f: Int -> Int -> Int
    f a b = a + b
the compiler (at least in Haskell) creates f as a function that takes a single argument, a, and outputs a function. That outputted function takes a single argument, b and outputs an Int.

When you apply the function f:

    f 5 7
what's really happening here is that f is first applied to 5. This creates a new function, call it g, taking in a single integer and outputting that integer plus 5. Then, this new function is applied to 7. (The compiler may optimize a lot of this away, but that is how you should think of what's happening in my opinion.)

Hope that helps!


I guess this comes back full circle to the original point: you should think of everything being left-associative here, so by default the above is interpreted as

    f: Int -> (Int -> Int)
    ...
    (f 5) 7


It's a function that takes a String and returns a new function which takes a String and returns a String. All functions in Haskell/Elm are arity 1.

So in order to construct functions that accept more than one argument, you actually return successive functions that apply successive arguments, known as currying.


This is really important when looking at it from "the outside" (or, one is too lazy to lookup the documentation ;-). Without knowing that, it could be a function that takes a string and compiles it to a function that takes two strings (ie: a macro, I guess). Or one string, and returns a string. Or...

Does this kind of 1/arity have performance implications for Haskell? Does the compiler lower (or is it rise? inline?) the functions to produce efficient machine code?


Thanks! Is this the case in Elm as well? This is the example they give:

  connectWords : String -> String -> String
  connectWords firstWord secondWord =
    firstWord ++ secondWord


In this case, you think of `connectWords` as a function that takes two arguments. But since it is curried, you can also do this:

    let prefix = connectWords "Hello "
        world  = prefix "world"
        bob    = prefix "bob"
    in ...
`world` is "Hello world", and `bob` is "Hello bob". That is the power of currying. A maybe more useful example is specifying the mapping function in `List.map` without supplying the list to map over. This allows you to use the same map with multiple lists.


Yes, all functions in Elm also have arity 1. That example desugars into this:

    connectWords = \ firstWord -> \ secondWord -> firstWord ++ secondWord




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: