Вычислить как можно большую часть списка за фиксированное время

Я хочу написать функцию, которая принимает ограничение по времени (в секундах )и список, и вычисляет как можно больше элементов списка в течение срока.

Моя первая попытка состояла в том, чтобы сначала написать следующую функцию, которая измеряет чистое вычисление и возвращает прошедшее время вместе с результатом:

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)

Мои вопросы:

  1. Как написать timeOut?
  2. Есть ли лучший способ написать функцию timeLimited, например, такую, которая не страдает от накопленной ошибки с плавающей запятой из-за многократного суммирования разницы во времени?
26
задан Chris Taylor 3 July 2012 в 23:00
поделиться