Бесконечный цикл в функциональном программировании?
Автор вопроса: symbiontОтветов: 4
Мне было интересно: можно ли делать бесконечные циклы в функциональном программировании?
Пример: при использовании Windows API для получения сообщений Windows это обычно реализуется в цикле.
Я знаю, что можно создать функцию, которая будет продолжать рекурсию бесконечно. Я ожидаю, что это приведет к переполнению стека.
бесконечный цикл - неправильный образ мышления для функционального программирования?
проблема в интерфейсе операционной системы или в оборудовании?
мне это не кажется функциональной программой / o.s. мог продолжать работать сам по себе
У меня небольшой опыт написания функциональных программ, но меня это всегда беспокоило. пожалуйста, поделитесь своими мыслями / идеями об этих проблемах
Как уже писали другие, бесконечный цикл возможен через хвостовые рекурсии .
Например. loop() будет эффективно работать как бесконечный цикл (в постоянном пространстве стека), поскольку компилятор может оптимизировать хвостовой рекурсивный вызов loop в конце.
let loop() = do {
println("foo")
loop()
}
Но
все еще есть точка. Рассмотрим ваш пример Windows-API с бесконечным циклом. Это совсем не функционально. Помните - функциональность означает мышление в ценностях (и в том, что они означают). Следовательно, предпочтительнее использовать реактивный / событийный подход, подобный этому [Псевдофункциональный код]
(onClick form1)
|> Event.subscribe (\pt-> do { print $ "I was clicked at " ++ (show pt) })
So
технически неверно - вы можете реализовать бесконечные циклы - но часто в этом нет (функционального) смысла. Зачем это нужно, кроме какого-то опроса ввода-вывода? Преобразование ценностей чисто функциональным образом должно прекратиться, чтобы иметь смысл.
Ответ 2 · рейтинг 5 · JohnB
Если вы используете хвостовую рекурсию, у вас фактически есть итерация, такая как цикл for / while. Следовательно, я думаю, у вас может быть бесконечный цикл без переполнения стека.
У вас может быть бесконечная хвостовая рекурсия, если ваш компилятор ее распознает. Некоторые языки, например схемы, требуют, чтобы компиляторы распознавали хвостовую рекурсию и не выделяли для нее место в стеке.
Изменить. Я не хочу не соглашаться с другими ответами, но "бесконечные" хвостовые рекурсивные циклы - это обычная идиома для работы с внешним миром. Следующий пример взят из Real World Haskell и является представителем этой идиомы.
mainloop :: Handle -> Handle -> IO ()
mainloop inh outh =
do ineof <- hIsEOF inh
if ineof
then return ()
else do inpStr <- hGetLine inh
hPutStrLn outh (map toUpper inpStr)
mainloop inh outh
Подавляющее большинство кода в чисто функциональной программе должно быть написано в полном подмножестве, то есть использовать шаблоны, такие как структурная рекурсия или совместная рекурсия (которые обеспечивают завершение и прогресс), а не возвращаться к общей рекурсии. Будем надеяться, что будущие версии GHC будут включать прямую поддержку для обнаружения некоторого полного подмножества Haskell и выдачи предупреждений для кода, для которого невозможно доказать завершение или прогресс.