Рендеринг значений в элементы и промежуточные элементы в Haskell

Dec 21 2020

При программировании пользовательского интерфейса я часто сталкиваюсь с необходимостью визуализировать список значений и добавить некоторую связанную информацию между визуализированными значениями. В следующем примере кода я визуализирую числовые значения в строках, где они отображаются в круглых скобках, и визуализирую расстояние между двумя значениями в строку, которая помещается между визуализацией значений. Код работает, но мне интересно, mysteryдоступна ли реализация функции как часть стандартной библиотеки Haskell. Меня также интересуют имена, используемые для этой функции в других библиотеках, поскольку использование удобочитаемых слов упрощает поиск в Google.

mystery :: (a -> b) -> (a -> a -> b) -> [a] -> [b]
mystery n d [] = []
mystery n d [x] = [n x]
mystery n d (x:xs) = (n x) : (d x (head xs)) : mystery n d xs

node x = "(" ++ show x ++ ")"
distance x y = "-" ++ (show $ abs $ x - y) ++ "-"
render xs = concat $ mystery node distance xs
-- render [25, 68, 54, 15] == "(25)-43-(68)-14-(54)-39-(15)"

Ответы

3 DDub Dec 21 2020 at 06:11

Ваша mysteryфункция на самом деле выполняет несколько действий одновременно, и если вы разделите поведение, может быть немного легче увидеть, что происходит.

Во-первых, вы наносите карту nна все элементы. Мы можем написать это как fmap n xs. Затем вы создаете новые элементы d x yдля всех пар смежных элементов xи y. Мы можем написать это как zipWith d xs (tail xs).

Последний шаг - взять эти две конструкции и создать новый список с элементами, которые чередуются между ними. Интересно, что этот вопрос задавали 9 лет назад , но до сих пор нет удовлетворительного ответа. Вероятно, самый простой ответ - определить свою собственную функцию:

alternate [] ys = ys
alternate (x:xs) ys = x : alternate ys xs

Затем мы можем определить mysteryкак однострочный:

mystery n d x = alternate (fmap n x) (zipWith d x (tail x))

Если вы действительно хотите, чтобы он был однострочным, лучшее, что я мог придумать, - это использовать concatи transposeв некоторой степени фанк:

mystery n d x = concat $ transpose $ (pure $ fmap n x) <> (pure $ zipWith d x (tail x))

По сути, мы составляем одноэлементные списки из двух компонентов, используя их pure, объединяя их вместе <>, затем transposeдобавляя этот «список списков», чтобы элементы правильно перемежались, и concatобрабатываем результат.