2014-02-16 62 views
1

我已經編寫了代碼來返回計算一系列整數的Func<int, long>。我想以最優雅的方式緩存中間結果。目前我的代碼看起來是這樣的:在C#中,我可以將Func包裝爲緩存結果

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; 
} 

我想它是這個樣子:

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; 
} 

這可能嗎?我如何編寫CachedFunc在返回時隱式地將CachedFunc轉換回Func,並隱式地將匿名lambdas轉換(包裝)爲緩存版本?如果不可能,最好的方式來包裝我的功能?我希望頂級代碼看起來儘可能簡單。

+0

這是某種家務?你的代碼有什麼問題?你如何衡量「最優雅」和「儘可能簡單」? – JeffRSon

+2

這被稱爲memoization。 – SLaks

+0

我正在尋找新的有趣的序列添加到OEIS。這個是https://oeis.org/draft/A237585。總的來說,我希望爲主要描述提供一段非常簡單的代碼,其中包含指向其他實現的鏈接。 –

回答

1

讓我們先看一個使用拉姆達爲明確捕獲類(這幾乎是相同的東西C#編譯器會自動創建時,看到一個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; 
    } 
} 

現在,我們只需要添加隱式轉換:

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; 
    } 
} 
+0

這是使用CachedFunc的代碼以及我得到的錯誤: CachedFunc A = null; CachedFunc B = null; CachedFunc C = null; ((n)=> n == 0?0:B(n-1));其中A =新Func B =(n)=> C(n)+(n == 1?1:0); C = CreateSumProductPartitionSelect(A,(n,k)=>選擇(n + k-1,k)); return A; 指定A表示「B是一個變量,但像方法一樣使用」。 指定B說:「不能將lambda表達式轉換爲鍵入CachedFunc ,因爲它不是委託類型」。 分配C作品就好了。 –

+0

@Guy:您不能在C#中調用用戶定義的對象。但是使用'B.Call(n-1)'(當然是公開的)應該不會很麻煩。而擴展方法可能有助於從lambdas分配這些對象。 –

+0

@Guy:順便說一句,我不確定你的原始代碼有什麼不好,如果你縮短了'CreateCachingFunc'的名字爲例如'memo' –

相關問題