Подтвердить что ты не робот

Haskell: удвоить каждый второй элемент в списке

Я только начал использовать Haskell и хотел написать функцию, которая, учитывая список, возвращает список, в котором каждый второй элемент был удвоен.

До сих пор я придумал следующее:

double_2nd :: [Int] -> [Int]
double_2nd [] = []
double_2nd (x:xs) = x : (2 * head xs) : double_2nd (tail xs)

Что работает, но мне было интересно, как вы, ребята, напишете эту функцию. Есть ли более общий/лучший способ или это выглядит правильно?

4b9b3361

Ответ 1

Это неплохо, по модулю предложенных исправлений. Как только вы познакомитесь с базовой библиотекой, вы, скорее всего, избегаете явной рекурсии в пользу некоторых функций более высокого уровня, например, вы можете создать список функций, где каждый другой *2 и применить (zip) этот список функции к вашему списку чисел:

double = zipWith ($) (cycle [id,(*2)])

Ответ 2

Вы можете избежать исключений "пустого списка" с помощью умного сопоставления с образцом.

double2nd (x:y:xs) = x : 2 * y : double2nd xs
double2nd a = a

это просто синтаксический сахар для следующего

double2nd xss = case xss of
    x:y:xs -> x : 2 * y : double2nd xs
    a -> a

сопоставление с образцом выполняется по порядку, поэтому сначала xs будет сопоставляться с образцом x:y:xs. Затем, если это не удастся, шаблон всеохвата a будет успешным.

Ответ 3

Немного некромантии, но я думаю, что этот метод очень хорошо работал у меня и хотел бы поделиться:

double2nd n = zipWith (*) n (cycle [1,2])

zipWith принимает функцию, а затем применяет эту функцию для сопоставления элементов в двух списках (первый элемент - первый элемент, второй элемент - второй элемент и т.д.). Функция - это умножение, а занесенный в список список - бесконечный цикл из 1s и 2s. zipWith (и все варианты zip) останавливается в конце более короткого списка.

Ответ 4

Попробуйте его в списке нечетной длины:

Prelude> double_2nd [1]
[1,*** Exception: Prelude.head: empty list

И вы можете увидеть проблему с вашим кодом. "Голова" и "хвост" никогда не являются хорошей идеей.

Ответ 5

Для нечетных списков или double_2nd [x] вы всегда можете добавить

    double_2nd (x:xs) | length xs == 0 = [x] 
                      | otherwise = x : (2 * head xs) : double_2nd (tail xs)

Спасибо.

Ответ 6

Здесь решение foldr -based.

bar :: Num a => [a] -> [a]
bar xs = foldr (\ x r f g -> f x (r g f)) 
               (\ _ _ -> []) 
               xs 
               (:)
               ((:) . (*2))

Тестирование:

> bar [1..9]
[1,4,3,8,5,12,7,16,9]