Опять про паттерн матчинг
На RSDN технические работы.
Хотел зацепиться в очередном флейме "ФВП vs паттерн-матчинг". Ребята показывали насколько ПМ сокращает код и проясняет его по сравнению с обычным императивным. А я пытался показать, насколько комбинаторы сокращают код и проясняют его по сравнению с ПМ. Ну и заодно показал пример как на основе equational reasoning можно улучшить код.
Продублирую, мне это было интересно - может ещё кому нибудь понравится.
Изначально, стояла такая задача (если я её верно понял):
Имеются вектор и двумерная матрица, надо перемножить вектор на столбцы матрицы, а затем сложить каждый столбец в одно число. Получим список чисел, количество которых равно количеству столбцов исходной матрицы, ну или длине строки матрицы.
Вообще то это подзадача, вторая подзадача там была - получение
Вот решение на Немерле с использованием паттерн-матчинга:
Удалены участки, относящиеся к вычислению
Вот первое пришедшее мне в голову решение на Haskell.
Плюс, помимо краткости и выразительности: мы можем легко сделать преобразования.
Сделать их можно, используя три закона
а также эта-редукцию и замену ($) на (.)
Всю цепочку показывать не буду - она тривиальна. Вот результат:
По моему короче, эффективнее и понятнее. Внутри сразу видно маленькую чётко очерченную подзадачку
P.S. А ещё я сегодня видел в метро парня, читавшего распечатку "Знакомство с языком Haskell" или что то в этом духе ;-)
P.P.S. А ещё я подумал, что изобрёл слово "индексикация" как перевод indexitis (болезнь использования (!!) в Haskell), а оно оказывается существует реально и означает совсем-совсем другое :-(
Хотел зацепиться в очередном флейме "ФВП vs паттерн-матчинг". Ребята показывали насколько ПМ сокращает код и проясняет его по сравнению с обычным императивным. А я пытался показать, насколько комбинаторы сокращают код и проясняют его по сравнению с ПМ. Ну и заодно показал пример как на основе equational reasoning можно улучшить код.
Продублирую, мне это было интересно - может ещё кому нибудь понравится.
Изначально, стояла такая задача (если я её верно понял):
Имеются вектор и двумерная матрица, надо перемножить вектор на столбцы матрицы, а затем сложить каждый столбец в одно число. Получим список чисел, количество которых равно количеству столбцов исходной матрицы, ну или длине строки матрицы.
Вообще то это подзадача, вторая подзадача там была - получение
init
списка, его тоже зачем то решали через ПМ (в Немерле нет аналога init
?).Вот решение на Немерле с использованием паттерн-матчинга:
def GetDx(_, _) { | ([ck], [cf]) => cf.Map(_ * ck) | (ck :: klast, cf :: flast) => def incDx = GetDx(klast, flast); cf.MapI((i, f) => f * ck + incDx[i]) | _ => throw Exception();//Если списки разной длинны. }
Удалены участки, относящиеся к вычислению
init
. MapI
- это map
с дополнительным параметром - индексом. Матрица в решении - это не список списков, как у меня на Haskell, а список массивов, так что MapI
применим, правда, по мне всё таки zipWith (\x y -> ck * x + y) cf incDx
понятнее.Вот первое пришедшее мне в голову решение на Haskell.
getDx ks fs = map sum $ transpose $ zipWith (\x -> map (x*)) ks fs
zipWith (\x -> map (x*)) ks fs
- переменожаем ks
на столбцы fs
map sum . transpose
- суммируем столбцыПлюс, помимо краткости и выразительности: мы можем легко сделать преобразования.
Сделать их можно, используя три закона
1. (f . g) . h == f . (g . h) 2. map f . map g == map (f . g) 3. transpose . zipWith (map . f) xs == map (zipWith f xs) . transpose
а также эта-редукцию и замену ($) на (.)
Всю цепочку показывать не буду - она тривиальна. Вот результат:
map (sum . zipWith (*) ks) $ transpose fs
По моему короче, эффективнее и понятнее. Внутри сразу видно маленькую чётко очерченную подзадачку
(sum . zipWith (*) ks)
- вектор на вектор, результат сложить. В случае паттерн-матчинга эта подзадачка раскидана по всему коду; сделать преобразование, подобное приведённому, гораздо сложнее.P.S. А ещё я сегодня видел в метро парня, читавшего распечатку "Знакомство с языком Haskell" или что то в этом духе ;-)
P.P.S. А ещё я подумал, что изобрёл слово "индексикация" как перевод indexitis (болезнь использования (!!) в Haskell), а оно оказывается существует реально и означает совсем-совсем другое :-(