我的應用程序使用FFT一個(昂貴的)變換後乘以向量。其結果是,當我寫Memoizing乘法
f :: (Num a) => a -> [a] -> [a]
f c xs = map (c*) xs
我只是想計算的c
的FFT一次,而不是爲xs
每個元素。實際上沒有必要爲整個程序存儲c
的FFT,只是在本地範圍內。
我試圖像來定義我的Num
例如:
data Foo = Scalar c
| Vec Bool v -- the bool indicates which domain v is in
instance Num Foo where
(*) (Scalar c) = \x -> case x of
Scalar d -> Scalar (c*d)
Vec b v-> Vec b $ map (c*) v
(*) v1 = let Vec True v = fft v1
in \x -> case x of
Scalar d -> Vec True $ map (c*) v
v2 -> Vec True $ zipWith (*) v (fft v2)
然後,在一個應用程序,我稱之爲類似於f
(其上的任意Num
作品),其中c=Vec False v
一個功能,我預期這將是一樣快,如果我砍f
到:
g :: Foo -> [Foo] -> [Foo]
g c xs = let c' = fft c
in map (c'*) xs
功能g
使fft c
發生的記憶化,並萬畝比呼叫f
快(不管我如何定義(*)
)。我不明白f
出了什麼問題。 Num
實例中是否是我對(*)
的定義?它有事情做與工作f
對所有訂購數量,因此GHC暫時無法弄清楚如何計算部分(*)
?
注意:我檢查了我的Num實例的核心輸出,並且(*)的確表示爲頂層lambda中FFT轉換的嵌套lambdas。所以看起來這至少能夠被記憶。我也嘗試了謹慎和魯莽地使用爆炸模式,試圖迫使評估毫無效果。
作爲一個側面說明,即使我可以計算出如何使(*)
memoize的第一個參數,還有它是如何定義的另一個問題:一個程序員想要使用的富數據類型有了解這種記憶能力。如果她寫了
map (*c) xs
不會發生記憶。 (它必須寫成(map (c*) xs))
現在我想到了,我不完全確定GHC如何重寫(*c)
版本,因爲我已經嘗試過(*)
但我做了一個快速測試,以驗證(*c)
和(c*)
都按預期工作: (c*)
使c
第一個參數爲*
,而(*c)
使c
第二個參數爲*
。所以問題在於如何寫乘法來確保記憶是不明顯的。這是否是中綴記號的固有缺點(和隱含的假設參數*
是對稱的)?
第二,那麼緊迫的問題是,情況WHE我們再映射(V *)到的標量列表。在這種情況下,(希望)v的fft將被計算和存儲,儘管由於另一個被乘數是標量是沒有必要的。有沒有辦法解決?
感謝
與'-O2'編譯和編譯代碼的標杆? – jberryman 2013-02-26 03:53:39
是的,但我沒有檢查覈心,它似乎沒有編譯任何東西。 – crockeea 2013-02-26 03:54:16
順便說一句,'讓c'= fft c在map(c *)xs' does * not *計算'fft',因爲Haskell是懶惰的。 'c''從不使用,所以它永遠不會被計算。 – luqui 2013-02-26 04:02:11