私のアプリケーションは、FFTを使用して(高価な)変換の後にベクトルを乗算します。私はメモ型の乗算
f :: (Num a) => a -> [a] -> [a]
f c xs = map (c*) xs
を書くときその結果、私はむしろ、xs
のすべての要素についてよりも、一度c
のFFTを計算したいです。実際には、プログラム全体のFFTをc
としてローカルスコープに格納する必要はありません。
私は次のように私のNum
インスタンスを定義しようとしました:そして、アプリケーションでは、私は(任意Num
の上で動作します)f
と同様の機能c=Vec False v
を呼び出して、私はこれはと予想さ
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)
g :: Foo -> [Foo] -> [Foo]
g c xs = let c' = fft c
in map (c'*) xs
機能g
fft c
のメモ化が起こりなり、ムーです:同じくらい速く、私はf
にはハックかのようになりますどのように私が(*)
を定義しても、f
を呼び出すよりも速くなります。 f
で何が問題になるのか分かりません。 Num
インスタンスの私の定義は(*)
ですか? f
がすべてのNumを扱うことと関係しているので、GHCは部分的に(*)
を計算する方法を見つけることができませんか?
Note:Numインスタンスのコア出力をチェックしましたが、(*)は実際にネストされたラムダとして表され、最上位のラムダにFFT変換されています。それで、少なくともこれはメモに記入することができるようです。また、評価を強制的に無効にしようとするために、賢明で無謀なバングパターンの使用を試みました。私は(*)
はその最初の引数をmemoize作成する方法を見つけ出すことができても、サイドノートとして
、それが定義されている方法で別の問題がまだある:使用したいプログラマは、Fooのデータ型が知っている必要がありこのメモ能力。彼女が書いた場合は、
map (*c) xs
は発生しませんでした。 ((map (c*) xs))
と書く必要があります。私は(*)
をカレーして以来、GHCが(*c)
バージョンをどのように書き換えるのかが完全にはわかりませんが、(*c)
と(c*)
の両方が期待通りに動作することを確認するためのクイックテストを行いました。 (c*)
をc
とすると、最初の引数は*
になりますが、(*c)
はc
になります。*
になります。 *
への引数が対称であるという暗黙の前提)?
第2の重要な問題は、 スカラーのリストにマップ(v *)します。この場合、(おそらく)vのfftは、他の被乗数がスカラーなので不要であるとしても、計算されて格納されます。これを回避する方法はありますか?
おかげ
に参照してください? – jberryman
はい、コアをチェックしましたが、何もコンパイルしていないようです。 – crockeea
ハスケルは怠惰なので、 'let c '= fft c(map *(c *)xs'は' fft'を計算しません)。 'c''は決して使用されないので、決して計算されません。 – luqui