制限時間 (秒単位) とリストを取り、制限時間内にリストの要素をできるだけ多く計算する関数を作成したいと考えています。
私の最初の試みは、最初に次の関数を作成することでした。この関数は、純粋な計算の時間を計測し、結果とともに経過時間を返します。
import Control.DeepSeq
import System.CPUTime
type Time = Double
timed :: (NFData a) => a -> IO (a, Time)
timed x = do t1 <- getCPUTime
r <- return $!! x
t2 <- getCPUTime
let diff = fromIntegral (t2 - t1) / 10^12
return (r, diff)
次に、これに関して必要な関数を定義できます。
timeLimited :: (NFData a) => Time -> [a] -> IO [a]
timeLimited remaining [] = return []
timeLimited remaining (x:xs) = if remaining < 0
then return []
else do
(y,t) <- timed x
ys <- timeLimited (remaining - t) xs
return (y:ys)
ただし、これは正しくありません。タイミング エラーや浮動小数点エラーを無視しても、このアプローチではリストの要素の計算が開始されると停止することはありません。
代わりに、時間がかかりすぎた場合に評価を短絡できる関数があったとします。
timeOut :: Time -> a -> IO (Maybe (a,t))
timeOut = undefined
次に、本当に必要な関数を記述できます。
timeLimited' :: Time -> [a] -> IO [a]
timeLimited' remaining [] = return []
timeLimited' remaining (x:xs) = do
result <- timeOut remaining x
case result of
Nothing -> return []
Just (y,t) -> do
ys <- timeLimited' (remaining - t) xs
return (y:ys)
私の質問は次のとおりです。
- どうやって書くの
timeOut
? - 関数を記述するためのより良い方法はあり
timeLimited
ますか?たとえば、時間差を複数回追加することによる浮動小数点エラーの蓄積に悩まされない方法はありますか?