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

Что использовать вместо основного цикла в Haskell?

Мне нужен цикл для main в Haskell. Я пробовал это:

main :: IO ()
main =
  do
    putStrLn "do something"
    main

Является ли приведенный выше код правильным подходом? Будет ли эта бесконечная рекурсия вызвать переполнение?

4b9b3361

Ответ 1

Это прекрасно; переполнение стека не произойдет. Переполнение стека в Haskell (и, действительно, любой нестрогий язык) отличается от на других языках; они возникают из-за накопления больших ценностей, никогда не оценивая их, но вы ничего не накапливаете; просто упорядочивая бесконечную цепочку действий. Вы можете подумать об этом так: как только строка будет напечатана, действие будет отброшено, и управление пройдет прямо на main; ничего не хранится в стеке, потому что ничего не нужно возвращать.

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

Тем не менее, более удобный способ написать этот конкретный пример:

import Control.Monad

main :: IO ()
main = forever $ putStrLn "do something"

Конечно, это не сработает, если ваш цикл когда-либо будет прерван. forever сам реализуется с рекурсией, поэтому нет никакой пользы, кроме читаемости для этого.

Ответ 2

То, что вы наблюдаете, является результатом "устранения/оптимизации хвостового вызова", что не имеет ничего общего с Haskell. См. http://en.wikipedia.org/wiki/Tail_call