Oblicz jak najwięcej listy w ustalonym czasie

Chcę napisać funkcję, która zajmuje limit czasu (w sekundach) i listę, i oblicza tyle elementów listy, ile to możliwe w określonym czasie.

Moją pierwszą próbą było najpierw napisanie następującej funkcji, która jest czasem obliczeń czystych i zwraca czas, który upłynął wraz z wynikiem:

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)

Mogę wtedy zdefiniować funkcję, którą chcę:

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)

To jednak nie do końca prawda. Nawet ignorując błędy czasowe i błędy zmiennoprzecinkowe, takie podejście nigdy nie zatrzymuje obliczania elementu listy po jego uruchomieniu, co oznacza, że ​​może (a właściwie normalnie) przekroczy swój limit czasowy.

Gdybym zamiast tego miał funkcję, która mogłaby spowodować zwarcie oceny, gdyby trwała zbyt długo:

timeOut :: Time -> a -> IO (Maybe (a,t))
timeOut = undefined

wtedy mógłbym napisać funkcję, którą janaprawdę chcieć:

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)

Moje pytania to:

Jak pisaćtimeOut?Czy jest lepszy sposób na napisanie funkcjitimeLimitedna przykład taki, który nie ma skumulowanego błędu zmiennoprzecinkowego z wielokrotnego dodawania różnic czasowych?

questionAnswers(3)

yourAnswerToTheQuestion