Вы почти на месте - но zipWith
сам возвращает список, поэтому вы не хотите помещать его в понимание списка, если только вы не хотите, чтобы результатом был список списков (чего здесь нет ).
zipWith (-)
здесь абсолютно правильная идея - она берет 2 списка и дает новый список, заданный разницей между соответствующими элементами данных списков. Ваш выходной список, в вашем случае, должен быть на 1 элемент короче, чем один входной список, и вы хотите использовать zipWith (-)
в 2 списках, которые состоят из:
- все элементы данного списка, кроме первого
- все элементы данного списка, кроме последнего
Haskell уже предоставляет нам удобные функции для них, а именно tail и init .
Итак, функция, которую вы ищете:
differences xs = zipWith (-) (tail xs) (init xs)
Обратите внимание, что это не идеально, потому что и init
, и tail
приведут к сбою вашей программы с ужасной ошибкой во время выполнения, если xs
пусто. Имеет смысл выводить пустой список, если вы представляете пустой список для этой функции (хотя вы можете утверждать, что это не так, поскольку вы получите пустой список из одноэлементного списка), поэтому вы можете избежать сбоя во время выполнения, определив функция через сопоставление с образцом для явного обслуживания пустого списка:
differences [] = []
differences xs = zipWith (-) (tail xs) (init xs)
Хотя лично я думаю, что это хорошо и очень явно, вам на самом деле не нужно использовать оба init
и tail
- zipWith
работает просто отлично, если представлены списки неравной длины, когда это просто обрежьте больший по размеру. Таким образом, differences xs = zipWith (-) (tail xs) xs
является жизнеспособной и несколько более краткой альтернативой.