Принятый ответ кажется кратким и очень эффективным, но его трудно рассуждать, особенно если вы новичок и пренебрегаете ленью Хаскелла.
Мы можем перефразировать его как
a = 1:2:2: (concat . zipWith replicate (drop 2 a) . cycle) [1, 2]
Мы должны помнитьa
- это просто полуструктурированный список, подобный 1:2:2:?: ... ?:[]
, и мы начинаем использовать его, просто отбрасывая первые два элемента (drop 2 a)
, что оставляет нам 2:?: ... ?:[]
для применения к zipWith replicate
, и этого достаточно для запусканаша логика неопределенна. Имейте в виду, 2:?: ... ?:[]
- это список, который должен быть рассчитан так же, как cycle [1,2]
. Наличие исходного элемента 2
позволяет рассчитать следующий элемент, а затем следующий элемент, а затем следующий и т. Д.
Это прекрасный шаблон в Haskell для генерации бесконечных списков, если вы знаетеначальные предметы. Возьмем, к примеру, серию Фибоначчи
fib = 1:1: (zipWith (+) fib (tail fib))
Все, что вам нужно сделать, это настроить ваше мышление, чтобы думать, что fib
уже существует, но еще не рассчитано.
Другой подходс Государственной Монадой:
Тем не менее, я считаю, что данная серия Колакоски также может быть хорошим примером для изучения Государственной монады. Давайте посмотрим, сможем ли мы получить такую же производительность ..?
import Control.Monad.Trans.State
invert :: Int -> Int
invert = (+1) . (`mod` 2)
rle :: Int -> State Int [Int]
rle n = state $ \s -> (replicate n s, invert s)
kolakoski :: [Int] -> Int -> [Int]
kolakoski ps s = ps ++ kolakoski xs i
where (xs,i) = runState (mapM rle ps >>= pure . concat) s
- У нас есть функция
invert
, когда с 1
дает 2
, а с 2
с 1
. rle
принимает тип Int
и возвращает тип State
, функцию, которая принимает состояние и реплицирует его на n
и возвращает реплицированный список вместе с новым состоянием,invert s
. Таким образом, наше состояние чередуется, например, 1,2,1,2...
.
Однако при тестировании с ghci (:set +s
), хотя оба демонстрируют линейную сложность по времени, для финализации требуется в 10 раз больше времени. Кто-нибудь хочет прокомментировать ..?