Haskell - Как преобразовать сумму карты (map (x:) xss) в карту (x+) (сумма карты xss)
Читая "Мышление функционально с Haskell", я натолкнулся на часть расчета программы, которая требовала, чтобы map sum (map (x:) xss)
быть переписан как map (x+) (map sum xss)
Интуитивно я знаю, что это имеет смысл...
если у вас есть несколько списков, которые вы собираетесь суммировать, но перед суммированием к тем же спискам вы также добавите один элемент 'x', то это то же самое, что взять список сумм оригинальных списков и добавить х значение для каждого из них.
Но я хотел бы знать, как преобразовать одно в другое, используя только рациональные рассуждения. Я чувствую, что мне не хватает закона или правила, которые помогли бы мне понять.
2 ответа
Используя закон
map f (map g list) === map (f . g) list
Мы можем вывести
map sum (map (x:) xss) =
map (sum . (x:)) xss =
Эта-расширить, чтобы дать аргумент для работы с
map (\xs -> sum . (x:) $ xs) xss =
Подставляя в (f . g) x === f (g x)
map (\xs -> sum (x:xs)) xs =
куда
sum (x:xs) = x + sum xs
sum [] = 0
так
map (\xs -> sum (x:xs)) xss =
map (\xs -> x + sum xs) xss =
Подставляя f (g x) === (f . g) x
map (\xs -> (x +) . sum $ xs) xss =
Эта-уменьшить лямбда
map ((x +) . sum) xss =
Использование обратного первого закона сверху
map (x+) (map sum xss)
Я рекомендую вам взглянуть на типы, и пусть они проведут вас через преобразование.
> let xss = [[1], [2], [3]]
> :t xss
xss :: Num t => [[t]]
> map sum xss -- basically compacting the lists
[1,2,3]
> :t map sum xss -- into just a list of numbers
map sum xss :: Num b => [b]
Далее нам нужно сделать сложение
> :t (+5)
(+5) :: Num a => a -> a
> :t map (+5) -- no magic in this
map (+5) :: Num b => [b] -> [b]
> map (+5) (map sum xss)
[6,7,8]
Суть в том, что в первом примере вы меняете типы не так, как во втором. Точка, в которой список списков становится просто списком, меняется, как и способ добавления номера.