4 ms·
> and in some cases you don't even need the |err| but since we're taking two arguments here you can't 'curry' it in a sense. This is extremely pedantic, but wi
by anyfoo 4y ago
> and in some cases you don't even need the |err| but since we're taking two arguments here you can't 'curry' it in a sense.
This is extremely pedantic, but without knowing Go, it looks like it's the other way around: Because you cannot curry the function "from"[1], you cannot do the partial application of "from" to "err" (which after currying would not really be a "partial application" but just application of the outermost function). Hence usage of what looks like a lambda.
[1] I guess currying is just not a thing in Go, because this looks like a straightforward case from a distance?
- steveklabnik 4y agoYeah to be honest I tossed the 's around curry because I didn't want to think about it too hard. You're right, and here's the more lengthy version for the curious. Just to be clear, I was speaking about Rust here, not Go. Rust doesn't really support "currying" exactly. What's happening here is this: The signature of map_err is pub fn map_err<F, O>(self, op: O) -> Result<T, F> where O: FnOnce(E) -> F, A method that takes a closure that implements FnOnce(E) -> F. I shouldn't have named it "from" because From::from in Rust has a different signature than we needed here, I'll call the version in this code "from_context" instead for the rest of this post: fn from(T) -> Self fn from_context<C, E>(context: C, error: E) -> Self (where C and E aren't exactly this but whatever it doesn't matter from what I'm trying to say here) We have an arity mismatch between these two. FnOnce takes one argument: the error. But in our version, we also want to tack on some context. If we didn't need two arguments, then we could simply pass the function as an argument, because function types in Rust also implement the closure traits in Rust. .map_err(OtherError::from)? Is that currying, exactly? It feels like it but I'd argue it's not. It's just a type implementing a trait, just like anything else. If Rust let you do .map_err(OtherError::from_context(someContext))?; I would argue that's currying support. You can do some sorts of currying in Rust, manually, but it's really awkward and 99.99% of the time you're not doing that.
- anyfoo 4y agoGood explanation! Wish I knew Rust (which I do often), now, instead of just Haskell, heheh. For anyone curious what "currying" actually is (I must say that I, for quite some time, made the mistake of thinking that taking a function that takes n arguments and getting a function that takes n-1 arguments (with one fixed) is "currying", which is not technically true, it's just a good thing you can do after currying): Currying is the act of taking a function that takes n arguments (or an n-tuple), and returning a new function with only one argument. But that function effectively wraps another function, and this repeats n times. So, you take e.g. this function: f(x,y,z) and currying makes this function: g(z) You see it only has one argument. But when you call that function with its only argument, the result is actually another function: h(y) There's our second argument. Call that and you get: i(x) And now you can call that with the first argument, and get the result. So after currying a function, you can just apply the last argument, and effectively get back a function with the last argument "fixed". Without that, you effectively have to use a lambda to fix the argument. (Or a combinator that does it for you.) Though you will need some sort of lambda or combinator anyway, if it's not the last argument you want to fix, but some other one. Then you have to create functions with stuff flipped around... Functions in Haskell usually take care that the last argument is the one where you'd most often want to fix it to a value.