Рассчитайте различия элементов списка, используя zipWith - PullRequest
0 голосов
/ 21 апреля 2019

Мне нужно создать функцию, называемую разностью, где я вычисляю разницу каждой пары с zipWith и помещаю ее в список.

Например, differences [1..5] == [1, 1, 1, 1].

.[2-1, 3-2, 4-3, 5-4] == [1, 1, 1, 1].

Я думал о создании списка кортежей, например:

[1..5] = [(1,2), (2,3), (3,4), (4,5)]

Затем используйте сжатие списка следующим образом:

[zipWith (-) a b | a <- y, b <- x]

где x - этопервый элемент кортежа, а y - второй.

Тип функции: differences :: Num a => [a] -> [a].

Ответы [ 3 ]

3 голосов
/ 21 апреля 2019

Вы почти на месте - но 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 является жизнеспособной и несколько более краткой альтернативой.

2 голосов
/ 21 апреля 2019

Построение Ответ Робина Зигмонда , экземпляр Applicative для функций хорошо работает здесь:

(f <*> g) xs == f xs (g xs)

, поэтому

differences = zipWith subtract <*> tail

(где subtract = flip (-).)

0 голосов
/ 22 апреля 2019

Как предлагает 4castle , используя drop 1 вместо tail в Второе решение init без Робина Зигмонда означает, что мы можем опустить случай [], так какdrop 1 [] = [] (в отличие от tail [], что приводит к ошибке времени выполнения):

differences xs = zipWith (-) (drop 1 xs) xs

В отличие от этого решения без явной деконструкции шаблона, я упомяну правописание, не использующее ни одного из init, tail и drop:

differences xs@(_:ys) = zipWith (-) ys xs
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...