Rendu des valeurs en éléments et éléments intermédiaires dans Haskell

Dec 21 2020

Lors de la programmation de l'interface utilisateur, je rencontre souvent le besoin de rendre une liste de valeurs et d'ajouter des informations connexes entre les valeurs rendues. Dans l'exemple de code suivant, je rend les valeurs numériques dans des chaînes où elles apparaissent entre parenthèses et rendent la distance de deux valeurs dans une chaîne qui est placée entre les rendus des valeurs. Le code fonctionne mais je me demande si une implémentation de la mysteryfonction est disponible dans le cadre de la bibliothèque standard Haskell. Je suis également intéressé par les noms utilisés pour cette fonction dans d'autres bibliothèques, car l'utilisation de mots lisibles par l'homme facilite la recherche sur 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)"

Réponses

3 DDub Dec 21 2020 at 06:11

Votre mysteryfonction fait en fait plusieurs choses à la fois, et si vous séparez les comportements, il peut être un peu plus facile de voir ce qui se passe.

Tout d'abord, vous mappez nsur tous les éléments. Nous pouvons écrire cela comme fmap n xs. Ensuite, vous construisez de nouveaux éléments d x ypour toutes les paires d'éléments adjacents xet y. Nous pouvons écrire cela comme zipWith d xs (tail xs).

La dernière étape consiste à prendre ces deux constructions et à faire une nouvelle liste avec des éléments qui alternent entre elles. Fait intéressant, c'était une question posée il y a 9 ans , mais elle n'a toujours pas de réponse très satisfaisante. La réponse la plus simple est probablement de définir votre propre fonction:

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

Ensuite, nous pouvons définir mysterycomme un one-liner:

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

Si vous voulez vraiment que ce soit un one-liner, le mieux que je puisse trouver était d'utiliser concatet transposed'une manière un peu funky:

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

Fondamentalement, nous créons des listes de singleton à partir des deux composants en utilisant pure, en les fusionnant avec <>, puis en transposecréant cette "liste de listes" pour obtenir les éléments correctement intercalés et en concatobtenant le résultat.