Как создать бесконечно повторяющийся список в Haskell?
Я парень c#, пытающийся научить себя Хаскеллу из веб-трансляций 9-го канала Эрика Мейера. Я наткнулся на интересную головоломку, которая включала пропуск всех " n " элементов списка с помощью zip и mod.
every :: Int -> [a] -> [a]
every _ [] = []
every n xs = [x | (x,i) <- zip xs [1..], i `mod` n == 0]
Я думал, что было бы более эффективно (для действительно больших списков или потоков), если бы мы могли избежать использования mod.
Я думал о лениво создании повторяющегося списка целых чисел, чтобы мы могли просто сравнить значение i с n.
repeatInts :: Int -> [Int]
такие этот зов repeatInts 3
возвращает [1,2,3,1,2,3,1,2,3,1,2,3,..]
ad infinitum.
учитывая это, мы могли бы переопределить every
вот так:
every :: Int -> [a] -> [a]
every _ [] = []
every n xs = [x | (x,i) <- zip xs (repeatInts n), i == n]
Итак, мои вопросы: как бы вы реализуете repeatInts
?
2 ответов
использовать cycle
:
cycle :: [a] -> [a]
cycle
связывает конечный список в круговой, или, что эквивалентно, бесконечное повторение исходного списка. Это тождество в бесконечных списках.
вы можете определить repeatInts
С точки зрения cycle
:
*Main> let repeatInts n = cycle [1..n]
*Main> :t repeatInts
repeatInts :: (Num t, Enum t) => t -> [t]
*Main> take 10 $ repeatInts 3
[1,2,3,1,2,3,1,2,3,1]
для любопытных, GHC инструменты cycle
С
cycle [] = errorEmptyList "cycle"
cycle xs = xs' where xs' = xs ++ xs'
в чисто функциональном языке, этот любопытный метод известен как брака, и он создает циклические структуры данных, а не бесконечные.
Подробнее см.
- "завязывание узла" на Haskell wiki
- "вступить в брак" в комментарии GHC
- "объяснение ‘брака’" здесь, на переполнение стека
- тег переполнения стека
[tying-the-knot]
поздний ответ, но он также может быть написан следующим образом:
repeatInts :: Int -> [Int]
repeatInts 0 = []
repeatInts a = [1..a] ++ repeatInts a