How to write a Curried add using macros

Hi! I'm new to Rust. I just learned how to write a Rust declarative macro following this repo yesterday but recursion is really confusing. I can't figure out how to write a curried add using macro or something more general than adding. Could you please post your code as reference?
Thank you for your generous help.

What is a "curried add"? What do you want your macro invocation to look like, and what do you want it to expand to?

I assume it's an add operation with an arbitrary number of operands? If so, here are two possible solutions (the one I'd use and one using recursion/TT munching):

macro_rules! add {
    ($($num:expr),*) => {
        0 $(
            + $num
        )*
    };
}

macro_rules! add_recursive {
    ($num:expr, $($tail:tt)*) => {
        $num + add_recursive!($($tail)*)
    };
    ($num:expr) => { $num };
}

fn main() {
    let x = 10;
    
    let res = add!(x, 1, 2, 3);
    
    let res_recursive = add_recursive!(x, 1, 2, 3);
    
    assert_eq!(res, 16);
    assert_eq!(res_recursive, 16);
}

Playground.

You should have a look at this: Incremental TT Munchers - The Little Book of Rust Macros. It describes how to write recursive declarative macros very well. In general, the little book of Rust macros is a very good read about macros in Rust.

1 Like

what I mean is something like this


// a common add may look like this:

let six_ = common_add(1,2,3);

assert_eq!(six_, 6);

// a curried one may look like this,

let add_1 = add!(1);

let three = add(1)(2);

assert_eq!(three, 3);

let six = add!(1)(2)(3);

assert_eq!(six, 6);

I mean it will work as this haskell one in this video


// a common one

add x y = x + y

// a curried one

add x = \y-> x+y

// a curried one

add = \x -> (\y -> x+y)

Thank you so much! That's what I want! :face_holding_back_tears: :star_struck:

Your requirement contradicts your statement that the above solution is what you want. The solution above is not curried. I reckon it's not actually currying that you need, but merely an arbitrary number of arguments?

If that is the case, the idiomatic Rust solution is not to use a macro but to write a function that accepts an iterator. Actually, the standard Sum trait can express this even without the need of writing a separate function:

let items: &[i64] = &[1, 2, 3];

let sum1: i64 = items[..0].iter().sum();
assert_eq!(sum1, 0);

let sum2: i64 = items[..2].iter().sum();
assert_eq!(sum2, 3);

let sum3: i64 = items.iter().sum();
assert_eq!(sum3, 6);
5 Likes

I agree with @H2CO3 that my solution is not curried add. I fiddled a little with the concept and I think you can achieve something that looks like curried add with push-down accumulation. As you can see though, this macro does not scale into infinity, so you can only implement curried add for up to five arguments (obviously you could increase the size of your macro to accommodate for cases 6 to how many more you need):

macro_rules! curried_add {
    (5) => {
        |x| move |y| curried_add!(4)(x + y)
    };
    (4) => {
        |x| move |y| curried_add!(3)(x + y)
    };
    (3) => {
        |x| move |y| curried_add!(2)(x + y)
    };
    (2) => {
        |x| move |y| curried_add!(1)(x + y)
    };
    (1) => {
        |z| z
    };
}

fn main() {
    let add3 = curried_add!(3);
    
    assert_eq!(add3(1)(2)(3), 6);
    
    let add5 = curried_add!(5);
    
    assert_eq!(add5(1)(2)(3)(4)(5), 15);
}

Playground.

2 Likes

Thank you so much! :kissing_closed_eyes:

Thank you so much :kissing_closed_eyes:

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.