Rendern von Werten in Elemente und Zwischenelemente in Haskell
Während der Programmierung der Benutzeroberfläche muss ich häufig eine Liste von Werten rendern und einige verwandte Informationen zwischen den gerenderten Werten hinzufügen. Im folgenden Codebeispiel rendere ich numerische Werte in Zeichenfolgen, die in Klammern stehen, und rendere den Abstand zweier Werte in eine Zeichenfolge, die zwischen den Darstellungen der Werte platziert wird. Der Code funktioniert, aber ich frage mich, ob eine Implementierung der mystery
Funktion als Teil der Haskell-Standardbibliothek verfügbar ist. Ich interessiere mich auch für Namen, die für diese Funktion in anderen Bibliotheken verwendet werden, da die Verwendung von lesbaren Wörtern das Googeln erleichtert.
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)"
Antworten
Ihre mystery
Funktion erledigt tatsächlich ein paar Dinge gleichzeitig, und wenn Sie die Verhaltensweisen trennen, ist es möglicherweise etwas einfacher zu sehen, was los ist.
Zunächst ordnen Sie n
alle Elemente zu. Wir können das schreiben als fmap n xs
. Als Nächstes erstellen Sie neue Elemente d x y
für alle Paare benachbarter Elemente x
und y
. Wir können das schreiben als zipWith d xs (tail xs)
.
Der letzte Schritt besteht darin, diese beiden Konstruktionen zu erstellen und eine neue Liste mit Elementen zu erstellen, die sich zwischen ihnen hin und her abwechseln. Interessanterweise war dies eine Frage, die vor 9 Jahren gestellt wurde , aber immer noch keine besonders zufriedenstellende Antwort hat. Die wahrscheinlich einfachste Antwort besteht darin, Ihre eigene Funktion zu definieren:
alternate [] ys = ys
alternate (x:xs) ys = x : alternate ys xs
Dann können wir mystery
als Einzeiler definieren:
mystery n d x = alternate (fmap n x) (zipWith d x (tail x))
Wenn Sie wirklich wollen , dass es einen Einzeiler sein, das Beste , was ich tun konnte, wurde mit concat
und transpose
in einem bisschen eine flippigen Art und Weise:
mystery n d x = concat $ transpose $ (pure $ fmap n x) <> (pure $ zipWith d x (tail x))
Grundsätzlich erstellen wir Singleton-Listen aus den beiden Komponenten pure
, indem wir sie miteinander verschmelzen <>
, dann transpose
diese "Liste der Listen" erstellen, um die Elemente richtig zu verteilen, und concat
das Ergebnis erstellen.