Using method directly instead of writing lambda

I was wondering why in Rust you can do:

iter.map(String::from)

But you can't do for example:

iter.map(re.captures)

Instead you have to do this:

iter.map(|s| re.captures(s))

Are there any reasons from the language design point of view as to why you can't just pass the method name instead of having to specify entire lambda?

Lack of currying, basically.

IOW Rust is not capable of turning 2-argument function into 1-argument function.

Haskell is famous for basing the whole language on that approach (among others, of course).

2 Likes

re.captures by itself can reference a struct field, but not a method (because that would be an incomplete type). You might think of it as Regex::captures(&re) or something like this, which is nonsensical because it is missing an argument! The only "partial functions" in Rust are closures.

In the other case, String::from is a function pointer, much like Regex::captures.

For a more concrete description, the Rust Reference indicates that re.captures (referring to a method) isn't even supported by the parser:

  1. Field access expressions - The Rust Reference (rust-lang.org)
  2. Method call expressions - The Rust Reference (rust-lang.org)

(I could be wrong, especially on the terminology. But this is my understanding.)

2 Likes

Short version of you answer is Rust doesn't support this because it doesn't support this.

I don't think it's particularly helpful answer.

On the other hand if you would user currying as keyword you can find few ideas discussed on IRLO.

The general consensus looks like it's just not worth it in a language built so very differently from Haskell.

But you may ask there again what they think about that idea. Using dot for currying certainly makes some sense, maybe someone there would explain why your idea is not good or maybe even adopt it if it would be deemed good enough.

Why are you replying to me as if I asked why this is not supported?

The one that comes to mind is that you can't call a field using re.field() either. You have to (re.field)() for that. As such, parse-time can tell which is happening.

iter.map(re.bla) doesn't indicate that it's supposed to be a method call instead of field access -- after all, iter.step_by(re.blah) should be a field, not a method, since it wants a usize.

2 Likes

Lack of currying is a fair explanation for this, but Python doesn't have currying either and they managed to get around this problem:

class MyClass:
    def __init__(self, a):
        self.a = a

    def my_method(self, n: int) -> int:
        return self.a + n


if __name__ == '__main__':
    c = MyClass(10)
    xs = list(map(c.my_method, [1, 2, 3, 4, 5]))
    print(xs)
    print(c.my_method)
kamov@msi:~/Desktop$ python ./main.py 
[11, 12, 13, 14, 15]
<bound method MyClass.my_method of <__main__.MyClass object at 0x7f9726290af0>>

This works, because methods in Python are a special type of functions which are bound to the object they come from, so they get automatically converted to the uncurried form by the Python interpreter. I'm not sure how feasible that would be though in Rust

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.