3 ms·
It's an interesting design question to pick orderings that work best with currying. Oddly though, when writing haskell code, I don't worry about it much. Once
by joeyh 12y ago
It's an interesting design question to pick orderings that work best with currying.
Oddly though, when writing haskell code, I don't worry about it much. Once I find myself needing to `flip` a function before using it, I have determined experimentally that the original parameter order I picked was not the best one, and I then go change the function, and let the type checker walk me through fixing any necessary call sites (which also verifies if the new parameter order is better or not).
- KMag 12y agoDepending on the size of your codebase, and the human and financial costs of a mistake, code reviewers may need strong justifications for function signature changes. Also, in my case, the language is gradually typed, so the type checker helps a lot, but doesn't disprove the possibility of runtime type errors.
- mikeash 12y agoI wonder why languages don't support currying arbitrary parameters. It seems like it would be easy enough to have a special "placeholder" keyword that means "these parameters will be the parameters of the curried function". To take his example: var jp = formatNames2('John', 'Paul'); That might be written like this instead: var jp = formatNames2('John', 'Paul', _); And then if you want to curry the second parameter instead of the third, it's easy: var jp = formatNames2('John', _, 'Jones'); Or maybe they do and I just haven't heard of it?
- netheril96 12y agoWell, C++ has it. It is called std::placeholders::_1, std::placeholders::_2, ...
- malisper 12y agoClojure[0] and Anarki[1] (public fork of Arc) both provide a way to do this (with more than one argument as well). They both have syntax for a "literal function". Your second example would become: Arc/Anarki: [format-names2 "John" _ "Jones"] which expands to (fn (_) (format-names2 "John" _ "Jones")) Clojure: #(format-names2 "John" % "Jones") which expands to (fn (%) (format names2 "John" % "Jones")) Then for a function of two arguments that curried the middle one: Anarki: [format-names2 _1 "Paul" _2] which expands to (fn (_1 _2) (format-names2 _1 "Paul" _2)) Clojure: #(format-names2 %1 "Paul" %2) which expands to (fn [%1 %2] (format-names2 %1 "Paul" %2)) [0] http://clojure.org/reader http://clojure.org/reader [1] https://github.com/arclanguage/anarki/blob/master/CHANGES/make-br-fn https://github.com/arclanguage/anarki/blob/master/CHANGES/ma...
- mikeash 12y agoI should have known that if I can imagine a language feature, it will already be implemented in the Lisps....
- KMag 12y agoI can think of both space/speed and syntactic reasons. The better argument is from syntax. You can think of partial function application as shorthand for lambdas. someFunc A B C = ... myFunc = someFunc "earlyParam" is shorthand for someFunc A B C = ... myFunc = \B C -> someFunc "earlyParam" B C Now, what syntax would you use for arbitrary order partial function application that's both elegant and more terse than just writing the lambda? (Also, if a compiler performs inlining to optimize partial function application, it's just as easy to perform the same optimizations for lambdas when the same information is available at compile time.) The space and time performance argument is weaker: If you have a language that compiles to native code, your calling convention passes everything on the stack (parameters on the right first), all parameters are the same size (as is the case for OCaml and other languages that pass everything as either a small integer or a pointer to a boxed value) and you only allow partial function application starting at the left parameter, then the partial function application native stubs for partially applying up to 10 parameters only requires 10 stubs. It's easy to include these stubs in your standard runtime, and the performance is very good. If the calling convention requires the callee to clean up the stack (Pascal/Windows Syscall calling convention), then the stubs don't even need to modify the return address, just copy the return address N words up the stack and copy in the partially applied parameters and then jump to the original function entry point. On the other hand, if you allow arbitrary Currying order, then the number of stubs explodes combinatorially and you're going to have to generate each stub in the compilation unit that needs it, maybe with a few common stubs in the standard runtime library. Of course, calling conventions with different parameter sizes and passing some parameters in registers complicates things, but you still wind up with a much simpler situation if you only allow partial application starting at one end of the parameter list. The syntax argument is more compelling.
- tel 12y agoFirstly, this is definitely partial application not currying (see my other post on this thread for great expansion on this point). Secondly, this is merely a syntactic item you're looking for. It's trivial to achieve this end in any language with first class anonymous functions. I'm not claiming that syntax isn't important, but instead just pointing out that it really is a trivial transformation to include if it were valuable enough.