web-dev-qa-db-ja.com

Haskellで評価を強制する方法は?

私は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日以上経過しているため、スタックオーバーフローに移動できませんでした。ですから、モデレーターの同意を得て、ここに質問を再投稿し、受け入れられた質問を自分で投稿します。これには、いくつかの有用な情報が含まれていると思います。

28
Giorgio

ユーザーが最初に与えた回答 ysdxプログラマーの場合

実際、あなたのバージョンはあなたのアルゴリズムをベンチマークしません。 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の完全/再帰的評価を強制する「魔法の」式です。

17
Giorgio

私は言語拡張を使用します -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)
9
J Fritsch