Рассмотрим два следующих варианта:
myReadListTailRecursive :: IO [String]
myReadListTailRecursive = go []
where
go :: [String] -> IO [String]
go l = do {
inp <- getLine;
if (inp == "") then
return l;
else go (inp:l);
}
myReadListOrdinary :: IO [String]
myReadListOrdinary = do
inp <- getLine
if inp == "" then
return []
else
do
moreInps <- myReadListOrdinary
return (inp:moreInps)
В обычных языках программирования можно было бы знать, что рекурсивный вариант хвоста является лучшим выбором.
Однако, пройдя этот ответ, очевидно, что реализация рекурсии haskell не похожа на реализацию повторного стека рекурсии.
Но поскольку в этом случае рассматриваемая программа включает в себя действия и строгую монаду, я не уверен, что применяются те же рассуждения. На самом деле, я думаю, что в случае IO
хвостовая рекурсивная форма действительно лучше. Я не уверен, как правильно рассуждать об этом.
EDIT: Дэвид Янг отметил, что самый внешний вызов здесь - (>>=)
. Даже в этом случае один из этих стилей имеет преимущество перед другим?