3 ms·
It's actually simpler in some ways, because we know that "a" must have arity 1. What we know is that "a" should be a function which takes a "b", that "a b" shou
by thinkpad20 13y ago
It's actually simpler in some ways, because we know that "a" must have arity 1. What we know is that "a" should be a function which takes a "b", that "a b" should be a function which takes a "c", and "a b c" should take a "d".
As a practical consideration, this rarely if ever becomes an issue, and if it does, the type checker will tell you straight away.
Type annotations can make clear what isn't intuitively clear with a function's signature, and since the correctness of the type checker is rigorously proven, I don't see anything particularly wrong with "relying" on the type checker.
- latk 13y agoThe argument that every function has arity 1 is technically true (this is the whole point of currying) but is not useful when definitions like "let a b c = ..." suggest other semantics. It's possible you've had a difference experience with this, but I tend to get confused when the semantic argument list isn't delimited. There is nothing wrong with relying on the type checker, except that it tends to add cognitive overhead.
- Peaker 13y ago"let a b c = ..." doesn't suggest other semantics. It's saying: "a applied to b, and then applied to c, equals ...". Note Haskell makes an effort to have the LHS of definitions imitate the exact syntax of function application. Patterns use the same syntax as data constructor applications.
- thinkpad20 13y agoIn my experience, the more you use currying, the more intuitive it becomes (surprise, surprise). In any case, you very quickly develop an understanding that `let foo bar baz = qux` is just syntactic sugar for `let foo = \bar -> \baz -> qux`. Of course, if you want to simulate higher-arity functions, you could just use tuples. It's perfectly acceptable to write `let foo(bar, baz) = qux`.
- mafribe 13y agoEvery function having arity 1 is reducing complexity. It's extremely uniform, and let a b c = ... is merely syntactic sugar for let a = (lambda b. (lambda c. ...)). It's very natural, and as Lisp/Scheme/Racket shows, it's perfectly fine in a dynamically typed context as well.