2

I want to be able to create a higher-order function (called g) that takes in a function (called f). g should pass in the first parameter to f and return a new function.

The use case is that I want to initiate a database connection in g and pass it functions that accept a database connection.

fn f1(a: i32, b: String) -> String {
    b
}

fn f2(a: i32, c: i64, d: i16) -> i32 {
    1000
}

fn g<T>(f: fn(a: i32, arbitrary_arguments_type) -> T) -> fn(arbitrary_arguments_type) -> T {
    move |arbitrary_arguments| f(1, arbitrary_arguments)
}

fn main() {
    g(f1)("hello".to_string());
    g(f2)(10, 11);
}

How do I create a macro that takes in as an argument a function with a more than 1 parameter, where first parameter is of a certain type, and supplies that argument for that first function?

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
z.f.s
  • 45
  • 6
  • Your f1 and f2 are to all accounts two different types, can you make their type signature similar? – yorodm Jan 16 '19 at 16:29
  • 1
    I believe your question is answered by the answers of [How do I emulate Lisp (apply) or (curry) in Rust?](https://stackoverflow.com/q/9271924/155423). If you disagree, please [edit] your question to explain the differences. Otherwise, we can mark this question as already answered. – Shepmaster Jan 16 '19 at 16:45
  • @yorodm The idea is that f1 and f2 will have different type signatures, the only similarity between them is that the first argument's will be identical. – z.f.s Jan 16 '19 at 17:14

1 Answers1

1

The specific question I'm having is how do I create a macro that takes in as an argument a function with a more than 1 parameter, where first parameter is of a certain type, supplies that argument for that first function.

Macros (even procedural macros) operate on syntax trees, so they can't change their behaviour based on semantics, including types and function arity. That means you'd have to have a different macro for each possible number of arguments. For example:

macro_rules! curry1 {
    ($func: ident, $($arg: expr),*) => {
        |a| $func($($arg),*, a)
    }
}

macro_rules! curry2 {
    ($func: ident, $($arg: expr),*) => {
        |a, b| $func($($arg),*, a, b)
    }
}

macro_rules! curry3 {
    ($func: ident, $($arg: expr),*) => {
        |a, b, c| $func($($arg),*, a, b, c)
    }
}

Which would be used like this:

fn f(a: i32, b: i32, c: i32) -> i32 {
    a + b + c
}

fn main() {
    // requires 2 extra args
    let f_2 = curry2!(f, 2);
    // requires 1 extra arg
    let f_2_1 = curry1!(f, 2, 1);

    println!("{}", f(2, 1, 3)); // 6
    println!("{}", f_2(1, 3));  // 6
    println!("{}", f_2_1(3));   // 6
}
Peter Hall
  • 53,120
  • 14
  • 139
  • 204