Representar valores en elementos y elementos intermedios en Haskell
Mientras hago la programación de la interfaz de usuario, a menudo encuentro la necesidad de representar una lista de valores y agregar información relacionada entre los valores representados. En el siguiente ejemplo de código, estoy renderizando valores numéricos en cadenas donde aparecen entre paréntesis y renderizo la distancia de dos valores en una cadena que se coloca entre las representaciones de los valores. El código funciona, pero me pregunto si una implementación de la mystery
función está disponible como parte de la biblioteca estándar de Haskell. También me interesan los nombres utilizados para esta función en otras bibliotecas, ya que el uso de palabras legibles por humanos facilita la búsqueda en 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)"
Respuestas
Su mystery
función en realidad es hacer un par de cosas a la vez, y si separa los comportamientos, puede ser un poco más fácil ver lo que está sucediendo.
Primero, estás mapeando n
todos los elementos. Podemos escribir eso como fmap n xs
. A continuación, está construyendo nuevos elementos d x y
para todos los pares de elementos adyacentes x
y y
. Podemos escribir eso como zipWith d xs (tail xs)
.
El último paso es tomar estas dos construcciones y hacer una nueva lista con elementos que se alternan entre ellos. Curiosamente, esta fue una pregunta que se hizo hace 9 años , pero aún no tiene una respuesta súper satisfactoria. Probablemente la respuesta más simple sea definir su propia función:
alternate [] ys = ys
alternate (x:xs) ys = x : alternate ys xs
Entonces, podemos definir mystery
como una línea:
mystery n d x = alternate (fmap n x) (zipWith d x (tail x))
Si realmente quieres que sea de una sola línea, lo mejor que se me ocurrió fue usar concat
y transpose
de una manera un poco original:
mystery n d x = concat $ transpose $ (pure $ fmap n x) <> (pure $ zipWith d x (tail x))
Básicamente, estamos haciendo listas singleton de los dos componentes usando pure
, fusionándolos con <>
, luego haciendo transpose
esta "lista de listas" para obtener los elementos correctamente intercalados y concat
obteniendo el resultado.