Вопрос

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