Calcule o máximo possível de uma lista em um horário fixo

Eu quero escrever uma função que leva um limite de tempo (em segundos) e uma lista e calcula tantos elementos da lista quanto possível dentro do limite de tempo.

Minha primeira tentativa foi primeiro escrever a seguinte função, que cronometra uma computação pura e retorna o tempo decorrido junto com o resultado:

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)

Eu posso então definir a função que quero em termos disso:

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)

Isso não está certo, no entanto. Mesmo ignorando os erros de temporização e os erros de ponto flutuante, esta abordagem nunca para o cálculo de um elemento da lista depois de iniciada, o que significa que pode (e de fato, normalmente) irá ultrapassar seu limite de tempo.

Se, em vez disso, eu tivesse uma função que pudesse fazer um curto-circuito na avaliação se demorasse demais:

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

então eu poderia escrever a função que eurealmente quer:

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)

Minhas perguntas são:

Como escrevotimeOut?Existe uma maneira melhor de escrever a funçãotimeLimited, por exemplo, aquele que não sofre de erro de ponto flutuante acumulado de adicionar diferenças de horário várias vezes?

questionAnswers(3)

yourAnswerToTheQuestion