Рендеринг значений в элементы и промежуточные элементы в Haskell
При программировании пользовательского интерфейса я часто сталкиваюсь с необходимостью визуализировать список значений и добавить некоторую связанную информацию между визуализированными значениями. В следующем примере кода я визуализирую числовые значения в строках, где они отображаются в круглых скобках, и визуализирую расстояние между двумя значениями в строку, которая помещается между визуализацией значений. Код работает, но мне интересно, 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)"
Ответы
Ваша 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
обрабатываем результат.