私はHaskellに比較的慣れていないので、do表記を使用してさまざまなアクションを順番に実行する方法を学ぼうとしています。特に、アルゴリズム(関数)のベンチマークを行うプログラムを書いています。
foo :: [String] -> [String]
この目的のために、私は次のような関数を書きたいと思います
import System.CPUTime
benchmark :: [String] -> IO Integer
benchmark inputList = do
start <- getCPUTime
let r = foo inputList
end <- getCPUTime
return (end - start) -- Possible conversion needed.
最後の行は変換(ミリ秒など)が必要な場合がありますが、これはこの質問のトピックではありません。
これは、引数inputListで関数fooを計算するのに必要な時間を測定する正しい方法ですか?
言い換えれば、式foo inputList
アクションの前に完全に削減されますend <- getCPUTime
実行されますか?または、r
はサンクにのみバインドされますfoo inputList
?
より一般的には、アクションが実行される前に式が完全に評価されるようにするにはどうすればよいですか?
この質問は数か月前にプログラマーに尋ねられ( ここ を参照)、そこで受け入れられた回答がありましたが、スタックオーバーフローに属しているため、トピック外としてクローズされました。質問は60日以上経過しているため、スタックオーバーフローに移動できませんでした。ですから、モデレーターの同意を得て、ここに質問を再投稿し、受け入れられた質問を自分で投稿します。これには、いくつかの有用な情報が含まれていると思います。
実際、あなたのバージョンはあなたのアルゴリズムをベンチマークしません。
r
は使用されないため、まったく評価されません。DeepSeq でそれを行うことができるはずです:
benchmark :: [String] -> IO Integer benchmark inputList = do start <- getCPUTime let r = foo inputList end <- r `deepseq` getCPUTime return (end - start)
(
a `deepseq` b
)は、a
を返す前にb
の完全/再帰的評価を強制する「魔法の」式です。
私は言語拡張を使用します -XBangPatterns 、私はそのような状況でそれが非常に表現力豊かであると思います。したがって、「let !r = foo inputList
"のように:
{-# LANGUAGE BangPatterns #-}
import System.CPUTime
benchmark :: [String] -> IO Integer
benchmark inputList = do
start <- getCPUTime
let !r = foo inputList
end <- getCPUTime
return (end - start)