Суммирование соответствующих пар из двух списков внутри кортежа - в Haskell

У меня есть кортеж, содержащий два списка чисел - ([1,2,3,4],[5,6,7,8])

Мне нужно суммировать соответствующие пары чисел из каждого списка. т.е. (1+5), (2+6) и т.д. Вывод списка т.е. [6,8,10,12]. Он также должен работать для любого количества элементов в списках (2 списка по 5, 2 списка по 6 и т. д.).

Я пытался использовать функцию, использующую «сумма карты. Транспонировать», но не могу правильно определить типы (так как она находится внутри кортежа). Я нашел здесь фрагмент кода, который работает для списка списков, но не знаю, как сделать то же самое для кортежа списков (возможно ли это?). Когда я пытаюсь изменить типы "a" или использовать Int, я компилирую ошибки несоответствия типов.

tupSums :: Num a => [[a]] -> [a]
tupSums = map sum . transpose

Я новичок в использовании Haskell, поэтому я не совсем понимаю ошибки, которые я получаю, извините, если вопрос покажется глупым.


person Worlt    schedule 14.02.2013    source источник


Ответы (1)


Это хороший кандидат на zipWith, который берет два списка и объединяет соответствующие элементы в списке с помощью определенного оператора. Следующее должно работать:

tupSums :: Num a => ([a],[a]) -> [a]
tupSums = uncurry $ zipWith (+)

zipWith (+) возвращает функцию, которая принимает два аргумента, каждый из которых является списком, и возвращает список попарных сумм. uncurry берет функцию двух аргументов и превращает ее в функцию, которая принимает один кортеж. Таким образом, uncurry $ zipWith (+) оценивается как функция, которая принимает кортеж списков и возвращает список с попарными суммами.

person Lily Ballard    schedule 14.02.2013
comment
Ура, Кевин, это большая помощь. В основном у меня возникают проблемы с различиями между [a] и [Int], что вызывает несоответствие типов при каррировании функций. - person Worlt; 14.02.2013
comment
@Worlt: Int — это конкретный тип, представляющий целое число. Он также принадлежит к классу типов Num, поэтому везде, где ожидается Num, вы можете использовать Int. Таким образом, в типе Num a => ([a],[a]) -> [a] вы можете передать ([Int],[Int]) на вход и получить [Int] на выходе. Единственным ограничением здесь является то, что конкретный тип всех трех списков должен быть одинаковым. Вы не можете пройти ([Int],[Integer]), и если вы пройдете ([Int],[Int]), вы не сможете получить [Integer] обратно. - person Lily Ballard; 14.02.2013
comment
@Worlt: Конечно, вы можете написать более сложную функцию с типом Num a, b, c => ([a],[b]) -> [c], если хотите, но, как правило, проще выполнять преобразования на вашем вводе/выводе, чем пытаться сделать саму функцию такой чрезвычайно общей. - person Lily Ballard; 14.02.2013
comment
Ах да, это имеет гораздо больше смысла, я думаю, что запутался в том, что на самом деле было. Кажется, это тип заполнителя для любого типа переменной, для которого вы его установили. Также - моя программа теперь полностью функциональна, большое спасибо! - person Worlt; 14.02.2013
comment
@Worlt: Да, если вы видите символ нижнего регистра как тип, это действительно просто заполнитель. Например, с id :: a -> a тип a является заполнителем для чего угодно. Но если один и тот же заполнитель используется дважды, он должен быть одного и того же типа оба раза, поэтому вы знаете, что id должен возвращать тот же тип, который был задан. А так как он ничего не знает об этом типе, вы знаете, что единственное, что id может вернуть, кроме основания, — это переданный ему аргумент. - person Lily Ballard; 14.02.2013
comment
@Worlt: Конечно, если вы видите Num a => a -> a, то вы знаете, что a не может быть чем угодно, это может быть только экземпляр класса типов Num. Но это может быть любой экземпляр, так что вы не знаете, Int это или Integer, или любой другой числовой тип. - person Lily Ballard; 14.02.2013
comment
@KevinBallard: Ах, основная проблема, с которой я столкнулся, заключалась в совпадении типов для a и Int, когда я пытался что-то mod, продолжал жаловаться на отсутствие Integral для [a], потребовалось некоторое время, чтобы это заработало, но теперь, похоже, работает! - person Worlt; 14.02.2013
comment
@Worlt: mod работает для всего в классе типов Integral. Если ваша функция объявлена ​​как принимающая [a], вы не можете mod элементы. Если заявлено, что он принимает Integral a => [a], то можно. - person Lily Ballard; 14.02.2013
comment
@KevinBallard: Это, вероятно, ужасно плохая практика, но мне, кажется, это сошло с рук, не указав типы моей функции и просто создав ее как map ('mod' 2). - person Worlt; 14.02.2013
comment
@Worlt: Во многих случаях не указывать типы вполне разумно. Явные объявления типов удобны в качестве документации и очень удобны для отлова ошибок (например, если функция выполняет проверку типа на неправильный тип, она поймает его там, а не там, где вызывается функция), и могут использоваться для сужения типа функции от тот, который может быть чрезмерно общим. Но специально для более простых функций это не нужно. - person Lily Ballard; 14.02.2013