1. 17

  2. 4

    There’s a few interesting things but something novel seems to be the syntax:

    def add_with_three(x, y):
      add_Int(add_Int(x, y), 3)

    Is exactly the same as:

    add_with_three = \x, y -> add_Int(add_Int(x, y), 3)

    Which is exactly the same as:

    add_with_three = \x -> \y -> add_Int(add_Int(x, y), 3)

    And these two are exactly the same:

    add(x, y)

    Something which seems to fall out of this combination of syntax and currying is that these two are the same:

    1. 4

      This is pretty common in pure functional programming languages inspired by Haskell and ML (and them by lambda calculus), it’s called automatic currying: multi-argument functions are just functions that return functions. In haskell, for example, a function like foo x y = x + y + 3 is just syntactic sugar for foo = \x y -> x + y + 3 or indeed foo = \x -> \y -> x + y + 3.

      What’s a little different here, it seems, is that add(x, y) exists as syntax, whereas in Haskell you write add x y which means (add x) y because function application is left-associative. Here, you write add(x, y) and it is interpreted as add(x)(y), which is a completely different idea. In Haskell a function that takes two arguments does exist, but in the form of a function that takes a tuple as an argument, the tuple being the single argument, and that is when you write add (x, y). It seems a little silly to be able to write add(x, y) and add(x)(y) when they mean the same thing, but I guess it makes sense if you want to use f(x) function call syntax.

      I expect, although I haven’t checked, that add(10) is probably equivalent to 10.add() rather than 10.add? That would fit with the Pythonic syntax better.

      1. 1

        I teach Haskell a lot so am super familiar with those details.

        I copied the 10.add example from their documentation so I don’t think that the 10.add() thing is true, but I can see how that might be expected and why syntax such as this can sometimes make things more confusing instead of less.

        1. 1

          Presumably you could then write 10.add(20) and maybe you could even write 20.(10.add), although presumably that would result in a function which takes zero arguments, which might contradict the docs, which say, “all functions are functions of a single argument” (Unless we can consider it to take some sort of ‘Unit’ type as its single argument?).

          1. 1

            20.(10.add) doesn’t make sense to me. The rules are x.f means f(x) and for nothing special we gain x.f(y) for free, being f(x)(y).

            These confusions might be indicating that the syntax is problematic.

            1. 1

              Ah I see, 20.(10.add) would be (10.add)(20) which is add(10)(20)

              1. 2

                (I didn’t reload, so I didn’t see this comment before I wrote the reply below)

                This . looks a bit like the reverse application operator, & from haskell’s lens package, possibly?

              2. 1

                I’m assuming that 20 is the x and 10.add is the function f, so in transforming x.f to f(x) we apply 10.add to 20. (I added extra parentheses because otherwise I assume 20.10 would be interpreted as some sort of floating point number instead. Presumably this wouldn’t be needed if the values were variables instead of literals.)