#haskell
Вопрос:
Я написал эту небольшую программу, и меня немного смущает ее поведение:
main = sequence $ iterate (printAdd =<<) (pure 0)
printAdd x = do
l <- getLine
let y = x read l
print y
pure y
Я ожидал, что он будет выводить сумму всех целых чисел каждый раз, когда я ввожу новое. Он работает более или менее, но аккумулятор неоднократно сбрасывается на 0. Этот сброс происходит после первого входа, после третьего входа, после шестого входа и так далее (т. Е. он всегда работает на один вход больше, чем раньше).
Почему это происходит?
Как я могу предотвратить это?
Ответ №1:
iterate
дает вам список все более длинных цепочек printAdd
.
iterate
возвращает список, в котором каждый элемент задается путем применения функции к предыдущему элементу. В документах вы можете увидеть эту иллюстрацию:
iterate f x == [x, f x, f (f x), ...]
В вашем случае, f = (printAdd =<<)
и. x = pure 0
Поэтому ваш список будет выглядеть следующим образом:
iterate (printAdd =<<) (pure 0) =
[pure 0, (printAdd =<< pure 0), (printAdd =<< printAdd =<< pure 0), ...]
Каждый N-й элемент будет представлять собой цепочку из N printAdd
вызовов, соединенных вместе, с нулем, введенным в первый
А затем sequence
просто выполняет все эти элементы по порядку. Нулевой ничего не делает, первый считывает одно число и печатает его, второй считывает число, печатает, затем считывает другое число, затем печатает сумму и так далее. Каждый N-й элемент считывает N чисел и выводит их скользящие суммы.
Комментарии:
1. Спасибо. В этом есть смысл. Поэтому, если я заранее знаю, что у меня будут
n
входные данные, я могsequence
бы заменить(!! n)
их . Но что мне делать, если я не хочу ограничивать количество вводимых данных?2. @kunberg Может быть какая-то предопределенная функция, которую вы могли бы использовать, но, вероятно, самый простой метод-это просто прямая рекурсия: в конце
printAdd
заменитеpure y
наprintAdd y
, а затем просто сделайтеmain = printAdd 0
.3. @кунберг, Ты мог
fix (printAdd >=>) 0
бы .