I've written code to return a Func<int, long> that computes a sequence of integers. I'd like to cache intermediate results in the most elegant way possible. Currently my code looks like this:

private static Func<int, long> A237585() {
    Func<int, long> A = null;
    Func<int, long> B = null;
    Func<int, long> C = null;
    A = CreateCachingFunc((n) => n == 0 ? 0 : B(n-1));
    B = CreateCachingFunc((n) => C(n) + (n == 1 ? 1 : 0));
    C = CreateCachingFunc(CreateSumProductPartitionSelect(A, (n, k) => Choose(n + k - 1, k)));
    return A;
}

private static Func<int, long> CreateCachingFunc(Func<int, long> original)
{
    var cache = new List<long>();
    Func<int, long> cachedVersion = (n) =>
    {
        while (n >= cache.Count) cache.Add(original(cache.Count));
        return cache[n];
    };
    return cachedVersion;
}

I'd like it to look something like this:

private static Func<int, long> A237585() {
    CachedFunc<long> A = null;
    CachedFunc<long> B = null;
    CachedFunc<long> C = null;
    A = (n) => n == 0 ? 0 : B(n-1);
    B = (n) => C(n) + (n == 1 ? 1 : 0);
    C = CreateSumProductPartitionSelect(A, (n, k) => Choose(n + k - 1, k));
    return A;
}

Is that possible? How would I write CachedFunc to implicitly convert the CachedFunc back to a Func on return, and implicitly convert (wrap) the anonymous lambdas into cached versions? If it's not possible, what's the nicest looking way to wrap my functions? I'd like the top level code to look as simple as I can.

有帮助吗?

解决方案

Let's first turn your existing memoization implementation that uses a lambda into an explicit capture class (this is almost identical to what the C# compiler creates automatically when it sees a lambda):

class CachedFunc<T>
{
     private List<T> cache;
     private Func<int, T> original;
     private T Call(int n)
     {
        while (n >= cache.Count) cache.Add(original(cache.Count));
        return cache[n];
     }

     public static Func<int, long> Create(Func<int, T> original)
     {
         return new CachedFunc<T>() { cache = new List<T>(), original = original }.Call;
     }
}

Now, we just need to add implicit conversion:

class CachedFunc<T>
{
     private List<T> cache;
     private Func<int, T> original;
     private T Call(int n) {
        while (n >= cache.Count) cache.Add(original(cache.Count));
        return cache[n];
     }

     public static implicit operator CachingFunc<T>(Func<int, T> original)
     {
         return new CachedFunc<T>() { cache = new List<T>(), original = original };
     }

     public static implicit operator Func<int, T>(CachingFunc<T> memo)
     {
         return memo.Call;
     }
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top