問題
Haskell で多値出力関数をシミュレートしたい。Haskell コードが生成されます (手書きではありません)。これは重要な情報です。以下を参照してください。
これはもちろん、次のように関数からタプルを返すことで簡単に実行できます。
f x y = (x+y, x-y)
しかし、そのような関数を使用するときは、それが返すタプルの種類を知る必要があります:
...
(out_f_1, out_f_2) = f a b
(out_g_1, out_g_2, out_g_3) = g out_f_1
...
など...しかし、コードを生成している間、fの出力のタイプがわからないので、現在、Data.List.Select
パッケージを使用して上記をシミュレートしています:
import Data.List.Select
...
out_f = f a b
out_g = g (sel1 outf)
...
問題はパフォーマンスです。私のテスト プログラムでは、使用するバージョンは、Data.List.Select
手動で記述したバージョンよりも 2 倍遅くなります。
andData.List.Select
を使用して記述されているため、これは非常に明白な状況です (私が間違っていない場合)。( http://hackage.haskell.org/packages/archive/tuple/0.2.0.1/doc/html/src/Data-Tuple-Select.html#sel1 )classes
instances
質問
Data.List.Select
手動で作成されたものと同じくらい高速になるようにバージョン (を使用する) を何らかの方法でコンパイルすることは可能ですか?
コンパイラーへの切り替えが必要だと思います。これにより、使用ごとにクラスとインターフェースを「インスタンス化」するように指示されます (C++ のテンプレートのようなもの)。
ベンチマーク
Test1.hs:
import qualified Data.Vector as V
import System.Environment
b :: Int -> Int
b x = x + 5
c x = b x + 1
d x = b x - 1
a x = c x + d x
main = do
putStrLn "Starting..."
args <- getArgs
let iternum = read (head args) :: Int in do
putStrLn $ show $ V.foldl' (+) 0 $ V.map (\i -> a (iternum-i))
$ V.enumFromTo 1 iternum
putStrLn "Done."
でコンパイルghc -O3 Test1.hs
Test2.hs:
import qualified Data.Vector as V
import Data.Tuple.Select
import Data.Tuple.OneTuple
import System.Environment
b x = OneTuple $ x + 5
c x = OneTuple $ (sel1 $ b x) + 1
d x = OneTuple $ (sel1 $ b x) - 1
a x = OneTuple $ (sel1 $ c x) + (sel1 $ d x)
main = do
putStrLn "Starting..."
args <- getArgs
let iternum = read (head args) :: Int in do
putStrLn $ show $ V.foldl' (+) 0 $ V.map (\i -> sel1 $ a (iternum-i))
$ V.enumFromTo 1 iternum
putStrLn "Done."
でコンパイルghc -O3 Test2.hs
結果
time ./Test1 10000000 = 5.54 s
time ./Test2 10000000 = 10.06 s