Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to define accumulator that can be infinitely chained as f(2)(3)(10)(100)?

If possible I want to define a function, for example as an accumulator, that can be infinitely chained as follows:

  • f(2) returns 2
  • f(2)(3) returns 5
  • f(2)(3)(10) returns 15
  • f(2)(3)(10)(100) returns 115
  • f(2)(3)(10)(100)()()... returns …
static void Main()
{
    Func<int, Func<int, int>> f = (x) =>
    {
        return (y) =>
        {
            return x += y;
        };
    };

    Console.WriteLine(f(2)(3));
    // Console.WriteLine(f(2)(3)(10)); should return 15

}

Any idea?

Note: I am not asking f(param int[] x){} approach.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

f cannot return an int, because you cannot invoke an int after calling f once. It can return a wrapper type that wraps an int though. f just needs to return the wrapper type, and then you can infinitely chain.

If you are fine with the indexer access syntax [...] instead of the method invocation syntax (...), then you can just create a struct like this:

struct F {
    public int Count { get; }
    
    private F(int count) {
        Count = count;
    }
    public F this[int acc] => new F(Count + acc);

    // override ToString to return Count.ToString,
    // or an implicit conversion to int, if you want
}

Then,

F f = new F(); // this could be a static field somewhere, making it effectively a global variable
Console.WriteLine(f[1][2][3][4].Count);

If you really like the method invocation syntax though, you would need to use dynamic and inherit from DynamicObject, overriding TryInvoke, like in this answer.

Example:

dynamic f = new F();
Console.WriteLine(f(1)(2)(3)(4).Count);

class F: DynamicObject {
    public int Count { get; }
    public F(int count = 0) {
        Count = count;
    }
    public override Boolean TryInvoke(InvokeBinder binder, object?[]? args, out object? result) {
        if (args?.Length == 1 && args?[0] is int acc) {
            result = new F(Count + acc);
            return true;
        }
        result = null;
        return false;
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading