Это моя первая публикация на SO, и я относительно новичок в Haskell, поэтому прошу прощения за любые ошибки или если мой код не идиоматичен!
Рассмотрим следующие два интуитивных описания: a, f(a), f (f (a)) ...
A. список, содержащий: a, применение f к a, применение f к , что, применение f к , что ...
B. список, содержащий в i-й позиции вложенные приложения f к a.
Моя проблема в том, что я сгорел, пытаясь использовать функцию iterate
в Haskell для выполнения A .Мое настоящее приложение - симуляция, но следующий надуманный пример выдвигает на первый план проблему.
import Control.Monad.State
example :: State Int [[String]]
step :: [String] -> State Int [String]
step l = do
currentState <- get
let result = if (currentState == 1)
then "foo":l
else "bar":l
put (currentState + 1)
return result
example = do
sequence $ take 3 . iterate (>>= step) $ return []
С этими определениями
evalState example 1
приводит к:
[[],["foo"],["bar","bar"]]
Очевидно, что iterate
делает B , а не A !Поскольку функция step
только когда-либо добавляет что-то в список ввода, step ["foo"]
не может привести к ["bar", "bar"]
, независимо от состояния!
Позвольте мне сказать, что я do понять, что здесь происходит, а также то, что - формально - результат в точности "как и должно быть": step
- это функция с состоянием, поэтому, когда f (a) подходит для оценки какчасть f (f (a)), она будет пересчитана, а не взята из второго элемента списка, потому что состояние изменилось.Я также понимаю, что мог бы избежать этого в своем реальном приложении, поместив свой накопительный список в состояние.
Тем не менее, есть две причины для публикации этого.
Во-первых, дело в том, чтоiterate
часто объясняется таким образом, что потенциально может ввести новичка в заблуждение, полагая, что он делает A , тогда как на самом деле это B .Это включает в себя Learn You A Haskell (что я иначе счел невероятно полезным), а также публикацию на SO ( здесь и здесь , например).Фактически, словесное объяснение iterate
в LYAHFGG - это почти точно определение A выше.Поэтому может быть полезно иметь пост на эту тему, который будет служить ресурсом для других новичков на Haskell, которые получают ошибку из-за этого и ищут объяснения (так что непременно публикуйте более точные, технические, лучше сформулированные пояснения поразница между A и B ниже).
Во-вторых, мне все равно будет интересно, есть ли функция, которая на самом деле выполняет A !Другими словами, как я могу в приведенном выше примере с состоянием создать список (с небольшим злоупотреблением обозначениями): [a, b = f (a), f (b), ...]?Другими словами, учитывая
example2 = do
firstResult <- step []
secondResult <- step firstResult
return $ [[], firstResult, secondResult]
, для которого
evalState example2 1
дает желаемый результат
[[],["foo"],["bar","foo"]]
Как я могу переписать example2
, используя iterate
?
В списке новичков на Haskell был опубликован связанный с вопрос относительно запоминающейся версии iterate
.Однако этот запрос, похоже, не получил ответа.
Я не совсем уверен, что лень действительно является проблемой в моем приложении.Будет ли строгая версия iterate
делать то, что я хочу?Моя собственная, наивная, «строгая итерация», как показано ниже, не имеет никакого значения.
iterate' f x = x : rest
where previous = f x
rest = previous `seq` iterate f previous
Любое понимание всего этого будет высоко ценится!