Я пытаюсь написать функцию, которая будет генерировать список, в котором первый элемент указан в качестве аргумента функции, а каждый последующий элемент будет отличаться максимум 1 от предыдущего элемента.Вот что я пробовал:
import Data.List
import System.Random
step :: Int -> IO Int
step n = (+n) <$> randomRIO (-1, 1)
steps :: Int -> Int -> IO [Int]
steps n = sequence . take n . iterate' (>>= step) . return
(я также пробовал с нестрогой функцией iterate
, которая дала мне тот же результат).
Функция step
принимаетinteger и, случайным образом, добавляет -1, 0 или 1 к нему.Функция steps
принимает количество итераций и начальное целое число и применяет step
правильное количество раз.
Проблема в том, что steps
дает мне такие вещи, как [0,1,-1,0,1,1,1,3]
, чтонеправильно.Похоже, каждый элемент создается каждый раз с нуля, тогда как я хочу, чтобы каждый элемент зависел от предыдущего.По этой причине я решил использовать iterate'
вместо iterate
, что говорит о том, что перед продолжением каждая итерация сводится к WHNF, но даже все равно это не работает.
Затем я понял, что проблема можетвозникают из-за того, что он на самом деле генерирует список, который выглядит примерно так:
[ n,
n >>= step,
n >>= step >>= step
... ]
И тогда кажется ясным, почему это происходит.Итак, мой вопрос, могу ли я предотвратить это?Могу ли я заставить Haskell оценивать каждый элемент по мере его продвижения?Существует ли строгая версия оператора >>=
?
(Правка: я подумал, что было бы полезно привести пример списка, который я ищу, а не просто описать его. [0, 1, 2, 1, 2, 1, 0, -1]
, например)