Как объясняют другие ответы, вы можете написать эту функцию рекурсивно из первых принципов, но я всегда думаю, что проблемы, подобные этим, являются интересными загадками: как вы можете составить такую функцию из существующей базовой библиотеки?
Во-первых, всякий раз, когда вы хотите проиндексировать список, вы можете zip
создать его с лениво вычисленным бесконечным списком:
Prelude> zip [0..] [1,5,2,8,4]
[(0,1),(1,5),(2,2),(3,8),(4,4)]
В этом случае вам не нужно знатьфактические значения индекса (0, 1, 2, 3, 4
и т. д.).Вместо этого вам просто нужно знать, сколько повторений каждого числа вам нужно.Вы можете получить это знание путем бесконечного циклического переключения между 2
и 1
:
Prelude> take 10 $ cycle [2,1]
[2,1,2,1,2,1,2,1,2,1]
(В приведенном выше примере для остановки списка используется take 10
, который, в противном случае, продолжается вечно.)
Вы можете zip (cycle [2,1])
с любым списком ввода, чтобы получить список кортежей:
Prelude> zip (cycle [2,1]) [1,5,2,8,4]
[(2,1),(1,5),(2,2),(1,8),(2,4)]
Первый элемент кортежа - это количество повторений второго элемента.
Вы можете использовать replicate
для повторения любого значения несколько раз, но вам придется uncurry
, чтобы принять один кортеж в качестве ввода:
Prelude> uncurry replicate (2,1)
[1,1]
Prelude> uncurry replicate (1,5)
[5]
Обратите внимание, что эта функция всегда возвращаетсписок, так что если вы сделаете это над списком кортежей, у вас будет список списков.Чтобы немедленно сгладить такой список, вы можете использовать монадное связывание для сглаживания проекции:
Prelude> zip (cycle [2,1]) [1,5,2,8,4] >>= uncurry replicate
[1,1,5,2,2,8,4,4]
Вы можете, если хотите, сделать из него функцию:
dup xs = zip (cycle [2,1]) xs >>= uncurry replicate
Эта функция оказывается параметрически полиморфной, поэтому, хотя вы можете использовать ее со списками целых чисел, вы также можете использовать ее со списками символов:
Prelude> dup [1,5,2,8,4]
[1,1,5,2,2,8,4,4]
Prelude> dup "acen"
"aaceen"