Macro with counter

I have some code like this:

entry.add_component(Component::<1>::default());
entry.add_component(Component::<2>::default());
entry.add_component(Component::<3>::default());

I want some macro to simplify the writing like this

macro_rules! add_component {
    ($entry:ident, $count:expr) => {
        $entry.add_component(Component::<$count>::default());
        add_component!($entry, { $count - 1 });
    };
    ($entry:ident, 0) => {};
}
add_component!(entry, 256);

But I can't figure out how to end the recursion, can somebody help? Thanks

This can't work, since macros does not evaluate the passed expressions during expansion. I.e., the first call will expand to:

entry.add_component(Component::<256>::default());
add_component!(entry, { 256 - 1 })

and the block will be preserved as-is, but the branch ($entry:ident, 0) expects literal zero and thus is never matched.

3 Likes

Yes, you are right, I have tried add_component(1,2,3,4,5,6.., 256), and it works

A nice trick here is to represent numbers in "base 0 1" (bijective numeration-wise):

macro_rules! add_component {(
    $entry:ident,
    $($fst:tt $($rest:tt)*)?
) => (
    $entry.add_component(Component::<0 $(+ $fst $(+ $rest)*)?>::default());
    $(
        add_component!($entry, $($rest)*);
    )?
)}

add_component!(entry,
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    
    
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
    1 1 1 1  1 1 1 1   1 1 1 1  1 1 1 1
);

Granted, 256 may be too big of a number for such an approach, but there is some elegance in the geometrical representation quantities :slightly_smiling_face:

4 Likes

Heh, I considered such an approach after poking at a possible logarithmic approach.

Nit: It's base 1.

1 Like

Go, binary!

macro_rules! add_component {
    ($entry:ident $($tokens:tt)*) => {
        add_component!{0, $entry $($tokens)*}
    };
    ($acc:expr, $entry:ident $token:tt $($tokens:tt)*) => {
        add_component!{2*$acc, $entry $($tokens)*}
        add_component!{2*$acc + 1, $entry $($tokens)*}
    };
    ($count:expr, $entry:ident) => {
        // add one here to start from 1
        // instead of from 0             vvvvvvvvvvvv
        $entry.add_component(Component::<{$count + 1}>::default());
    };
}

fn main() {
    let entry = …;
    add_component!(entry #### ####); // 8 tokens after `entry` for 2^8 == 256 possibilities
}

(playground)

6 Likes

Go, any base!

macro_rules! add_component {
    (# ($($acc:expr),*) $remaining_args:tt) => {
        $(add_component!{$acc, $remaining_args})*
    };
    ($entry:ident $offset:literal $base:literal $digits:tt $($tokens:tt)*) => {
        add_component!{0, ($entry $offset $base $digits $($tokens)*)}
    };
    ($acc:expr, ($entry:ident $offset:literal $base:literal [$($digit:literal)*] $token:tt $($tokens:tt)*)) => {
        add_component!{# ($($base*$acc+$digit),*)($entry $offset $base [$($digit)*] $($tokens)*)}
    };
    ($count:expr, ($entry:ident $offset:literal $base:literal $digits:tt)) => {
        $entry.add_component(Component::<{$count + $offset}>::default());
    };
}

fn main() {
    let entry = …;
    
    // multiple examples
    
    add_component!(entry 1 2 [0 1] #### ####); // 1 to 256
    
    add_component!(entry 100 10 [0 1 2 3 4 5 6 7 8 9] ##); // 100 to 199
    
    add_component!(entry 1 4 [0 1 2 3] ####); // 1 to 256 (base 4)
}

(playground)

3 Likes

Yeah, I should have said no-base rather than base 0, my bad. I personally disagree that tally marks would be base 1 or at least, we can say it's not a genuine base numeration system: if we amended some of the rules for numeral representation in base 𝒷, then we could map a tally system to it, but it's far-fetched. I thus prefer to see it as a base-less representation (or, in another far-fetched approach: base ∞, where the digits come from the tally system :upside_down_face: )

I guess, if you want it to be some form of genuine “base 1 numeration system”, it counts best as an instance of bijective numeration which are awefully similar to “ordinary” positional notation but not quite the same.

3 Likes

It seems like a pretty good match to me: In a base b system, the digit in position k is multiplied by bk. These results are then summed to find the represented number. As 1k = 1, every digit present contributes a unit to the result, which is a tally system.

2 Likes

Yeah but the only usable digit in base 1 is 0; the digit 1 does not exist.

That's an interesting generalization of "classic bases", and one which seems to allow the digit to be equal to the base!

Given that, and how it (quite ambiguously, imho) carries the name "base" alongside it, I withdraw my skepticism: it seems it's not that far fetched to think of a system where the digits can be equal to the base, after all :grinning_face_with_smiling_eyes: Thanks for the pointer @steffahn!

1 Like

Noteworthy section out of that article:

The bijective base-26 system [edit]

In the bijective base-26 system one may use the Latin alphabet letters "A" to "Z" to represent the 26 digit values one to twenty-six. (A=1, B=2, C=3, ..., Z=26)

With this choice of notation, the number sequence (starting from 1) begins A, B, C, ..., X, Y, Z, AA, AB, AC, ..., AX, AY, AZ, BA, BB, BC, ...

Each digit position represents a power of twenty-six, so for example, the numeral ABC represents the value 1 × 262 + 2 × 261 + 3 × 260 = 731 in base 10.

Many spreadsheets including Microsoft Excel use this system to assign labels to the columns of a spreadsheet, starting A, B, C, ..., Z, AA, AB, ..., AZ, BA, ..., ZZ, AAA, etc. For instance, in Excel 2013, there can be up to 16384 columns, labeled from A to XFD.[3] A variant of this system is used to name variable stars.[4] It can be applied to any problem where a systematic naming using letters is desired, while using the shortest possible strings.

So it really isn’t that unfamiliar if you ever used Excel :grin:

1 Like