Подтвердить что ты не робот

Как избежать в Haskell?

Haskell не поддерживает циклическое вычисление, вместо этого он предлагает использовать алгоритмы рекурсии. Но этот подход приводит к росту стека и даже переполнению стека. Я считаю, что должен быть подход к решению этой проблемы в целом. Вот образец. Я хотел знать, сколько раз getClockTime может вызываться в течение 5 секунд:

import System.Time

nSeconds = 5

main = do
    initTime <- totalPicoSeconds `fmap` getClockTime
    doWork initTime 1
    where
    doWork initTime n = do
        currTime <- totalPicoSeconds `fmap` getClockTime
        if (currTime - initTime) `div` 10 ^ 12 >= nSeconds
            then print n
            else doWork initTime (n+1)

totalPicoSeconds :: ClockTime -> Integer
totalPicoSeconds (TOD a b) = a * 10 ^ 12 + b

Программа длится 5 секунд, но в итоге я получаю:

Переполнение пространства стека: текущий размер 8388608 байт.
Используйте `+ RTS -Ksize -RTS ', чтобы увеличить его.

Ручное управление размером стека может помочь в конкретном случае, но если я захочу запустить этот алгоритм в течение 10 секунд, он может снова переполняться. Так что это не решение. Как я могу заставить этот код работать?

4b9b3361

Ответ 1

Проблема здесь не в рекурсии, а в лень вашего аргумента n. Переполнение стека в Haskell происходит от попытки оценить глубоко вложенные трюки; в вашем случае каждый вызов doWork initTime (n+1) делает во втором аргументе слегка глубже вложенный тон. Просто сделайте это строгим, и все должно быть счастливым снова: doWork initTime $! n+1.