Повторение Хаскелла (f :: IO a -> IO a)

#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 бы .