Я новичок в Haskell, и мне нравится идея замены циклов рекурсией. Я возился с проектом для домашних животных, и я хотел протестировать некоторые функции ввода текста, поэтому я написал небольшой интерфейс командной строки, который неоднократно запрашивает ввод, пока не получит определенную команду quit. Это выглядит примерно так:
getCommandsFromUser = do
putStrLn "Enter command: "
keyboardInput <- getLine
let command = map toLower keyboardInput
if command == "quit"
then
putStrLn "Good-bye!"
else do
-- stuff
-- more stuff
putStrLn ("Sending command: " ++ commandURI)
simpleHTTP $ getRequest commandURI
getCommandsFromUser
main = do
getCommandsFromUser
Это работает точно так, как ожидалось, но, исходя из фона C/Java, он все еще щекочет глубокие, темные, бессознательные части моего мозга и заставляет меня хотеть вырваться в ульях, потому что я не могу поколебать мысль о том, что каждый рекурсивный вызов getCommandsFromUser
заключается в создании нового фрейма стека.
Теперь я ничего не знаю об IO, монадах, штате, стрелках и т.д. Я все еще работаю через Real World Haskell, я еще не дошел до этой части, и некоторые из этого кода соответствуют шаблону, который я нашел в Google. Кроме того, я знаю, что весь смысл GHC заключается в том, что он безумно оптимизирующий компилятор, который предназначен для совершения невероятных вещей, таких как прекрасное разворачивание хвостовых рекурсивных функций и тому подобное. Так может кто-нибудь объяснить, является ли эта реализация "правильной", и если это так объясняет мне, что происходит за кулисами, которые помешали бы этой программе взорваться, если бы она была поставлена в руки бесконечного числа обезьян?
Изменить для ясности: я знаю, какая оптимизация хвостового вызова. Я упомянул об этом выше, но я расскажу об этом еще раз. Меня больше волнует, как это работает в этом случае, что происходит с действиями и общей функциональной примесью.
Double Edit: Большое спасибо за все потрясающие ответы. Оглядываясь назад, я не думаю, что я правильно сформулировал вопрос, но у меня все еще есть то, что я искал. Этот вопрос был не столько основан на идее, что я был смущен тем, как Хаскелл использовал стек, и я ожидал, что он будет работать как императивный язык; это было основано на том, что я понятия не имел, как Haskell обрабатывал стек и хотел знать, что он делает иначе, чем традиционные C-подобные языки. Я просыпаюсь с умным человеком благодаря вам.