Тайм-аут чистых функций

Как я могу "убить" чистый расчет, который занимает слишком много времени? Я старался

<code>import System.Timeout

fact 0 = 1
fact n = n * (fact $ n - 1)

main = do maybeNum <- timeout (10 ^ 7) $ (return . fact) 99999999
          print maybeNum
</code>

Однако это не работает. Заменить(return . fact) 99999999 с "реальным" IO функционирует какgetLine и это работает как ожидалось.

 Matvey Aksenov09 апр. 2012 г., 12:04
Интересно, что еслиfact стать "реальным" IO action (fact 0 = return 1; fact n = (n *) `fmap` (fact $ n - 1)) затемtimeout тоже работает как положено
 leftaroundabout09 апр. 2012 г., 12:11
@ MatveyAksenov: я думаю, что это не так, потому что функция - это реальное действие ввода-вывода, а потому, что ее рекурсия осуществляется посредствомfmapпереехал вIO монада.
 Ganesh Sittampalam19 апр. 2012 г., 13:28
Если вам нужно тайм-аут произвольного и потенциально вредоносного кода, обязательно проверьте действительно простые невыделенные циклы, например,let x = x in x а такжеlet x () = x () in x ().

Ответы на вопрос(1)

Решение Вопроса

Дело в том, что

return (fact 999999999)

немедленно возвращается и не запускает тайм-аут. Возвращает thunk, который будет оценен позже.

Если вы форсируете оценку возвращаемого значения,

main = do maybeNum <- timeout (10 ^ 7) $ return $! fact 99999999
          print maybeNum

это должно вызвать тайм-аут (если вы предоставляете стек достаточно большой, чтобы тайм-аут происходил до переполнения стека).

Ваш ответ на вопрос