6 ms·
I enjoy reading and writing "Functional" code in a language where the ergonomics lend themselves to functional semantics. That swift code is painful to read. I'
by weatherlight 3y ago
I enjoy reading and writing "Functional" code in a language where the ergonomics lend themselves to functional semantics.
That swift code is painful to read.
I'll give some examples (from worst to best.)
Java: (awful, to read and write)
import java.util.function.Function;
public class Main {
public static void main(String[] args) {
Function<Integer, Function<Integer, Integer>> add = x -> y -> x + y;
Function<Integer, Integer> addFive = add.apply(5);
int result = addFive.apply(3); // Output will be 8
}
Ruby a. (still not great, but there's many ways to do it!)
add = proc { |x, y| x + y }
curried_add = add.curry
add_five = curried_add.call(5)
result = add_five.call(3)
}
Ruby b. (slightly more concise)
add = ->(x) { ->(y) { x + y } }
add_five = add.(5)
result = add_five.(3)
Elixir (functional programing lang but doesn't lean on currying too much)
add = fn x -> (fn y -> x + y end) end
add_five = add.(5)
result = add_five.(3)
ES6 (say what you want about javascript but they at least did arrow functions right)
const add = x => y => x + y;
const addFive = add(5);
const result = addFive(3);
Standard ML (clearly a lang where currying is a first class concern in its language design)
fun add x y = x + y;
val addFive = add 5;
val result = addFive 3;
and finally Haskell (which, in this case is a joy to read and write.)
add x y = x + y
addFive = add 5
result = addFive 3
- saghm 3y agoJava has (limited) type inference now I think, right? Does this work for the example you gave? public class Main { public static void main(String[] args) { var add = x -> y -> x + y; var addFive = add.apply(5); int result = addFive.apply(3); // Output will be 8 } } Still not great, but a lot better than the original IMO
- danhau 3y agoNo, I don’t think that works. Last time I checked, type inference doesn‘t work for lambda expressions. Part of the reason - I think - is that lambda expressions need to be boiled down to some concrete @FunctionaInterface interface. You can have arbitrarily many of these, all with the same signature and method name, so language doesn‘t know which to choose.
- _old_dude_ 3y agoYou need an helper method for that public class Main { private static <T,R> Function<T,R> fun(Function<T,R> function) { return function; } public static void main(String[] args) { var add = fun(x -> fun(y -> x + y)); var addFive = add.apply(5); int result = addFive.apply(3); // Output will be 8 } } Those helpers should be part of the JDK.
- mumblemumble 3y agoThrow a checked exception in there and it all goes to hell all over again.
- Someone 3y ago> That swift code is painful to read. I you mean the Swift code in the article, that almost looks like Kotlin :-) Swift requires type constraints on the original add function, but infers them for addFive. func add<T> (x:T, y:T) -> T where T: Numeric { x + y } let addFive = {(y) in add(x: 5, y: y)} let result = addFive(3) Edit: in Swift 3, one could write func add<T>(x:T)(y:T) -> T where T: Numeric { return x + y } and call that as add(x: 2)(y: 3) or, in two steps, as let addTwo = add(2) addTwo(3) That functionality was removed, though. For reasoning behind that, see https://github.com/apple/swift-evolution/blob/main/proposals/0002-remove-currying.md https://github.com/apple/swift-evolution/blob/main/proposals....
- weatherlight 3y agoI meant Kotlin, i totally whiffed. (can you tell i don't write Swift or Kotlin?) :) (Swift for currying, based on your example, isn't terrible actually!)
- eddtests 3y agoWhen we talk about Currying I can grok these, but if I saw that ES6 example in the wild and FP isn’t on my mind I’d be so confused when reasoning about it, especially if it was more complex than adding. Haskell better be good at Currying since it’s named after https://en.m.wikipedia.org/wiki/Haskell_Curry https://en.m.wikipedia.org/wiki/Haskell_Curry
- cies 3y agoI loved Ruby: an OO lang with some FP on top where it makes sense. I found Kotlin to be very similar to Ruby: primary on OO lang with FP on top where it makes sense, but now with compile-time types (slightly but fundamentally better than Java's) built in. The main thing I miss in Kotlin is proper, first-class sum types. There is a trick with using inheritance to achieve it, but not good enough for me. They've become a fundamental tool for me (same level as record (data class) and collections). I get how that would make Java-interop much harder, and that that's likely why they've been left out.
- mackman 3y agoC++14 standard: auto add = [](auto x) { return [x](auto y) { return x + y; }; }; auto addFive = add(5); auto result = addFive(3);
- mathisfun123 3y agoThis isn't currying at all because each call to add builds a completely new (internal) representation of the addition function.
- rmilejczz 3y agoCurrying looks surprisingly great in JavaScript
- weatherlight 3y agoIt does!
- jabradoodle 3y agoClojure is really nice here: (let [add-five (partial + 5)] (add-five 3)) The add-five function can take any number of arguments, including 0.
- tripdout 3y agoThe Nix language is similarly nice: (assume the following is inside a let block) add = x: y: x + y addFive = add 5 result = addFive 3
- weatherlight 3y ago<3 nix & NixOS
- minebreaker 3y agoScala def add(x: Int)(y: Int) = x + y def addFive = add(5)(_) val result = addFive(3)