Renderizando valores em itens e itens intermediários em Haskell
Ao fazer a programação da interface do usuário, muitas vezes encontro a necessidade de renderizar uma lista de valores e adicionar algumas informações relacionadas entre os valores renderizados. No exemplo de código a seguir, estou renderizando valores numéricos em strings onde aparecem entre parênteses e renderizando a distância de dois valores em uma string que é colocada entre as renderizações dos valores. O código funciona, mas estou me perguntando se uma implementação da mysteryfunção está disponível como parte da biblioteca padrão Haskell. Também estou interessado em nomes usados para essa função em outras bibliotecas, pois o uso de palavras legíveis por humanos torna a busca no Google mais fácil.
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)"
Respostas
mysteryNa verdade, sua função está fazendo algumas coisas ao mesmo tempo e, se você separar os comportamentos, pode ser um pouco mais fácil ver o que está acontecendo.
Primeiro, você está mapeando ntodos os elementos. Podemos escrever isso como fmap n xs. Em seguida, você está construindo novos elementos d x ypara todos os pares de elementos adjacentes xe y. Podemos escrever isso como zipWith d xs (tail xs).
A última etapa é pegar essas duas construções e fazer uma nova lista com elementos que se alternam entre elas. Curiosamente, esta foi uma pergunta feita há 9 anos , mas ainda não tem uma resposta super satisfatória. Provavelmente, a resposta mais simples é definir sua própria função:
alternate [] ys = ys
alternate (x:xs) ys = x : alternate ys xs
Então, podemos definir mysterycomo uma linha:
mystery n d x = alternate (fmap n x) (zipWith d x (tail x))
Se você realmente quer que seja um one-liner, o melhor que eu consegui foi usar concate transposede uma maneira um pouco descolada:
mystery n d x = concat $ transpose $ (pure $ fmap n x) <> (pure $ zipWith d x (tail x))
Basicamente, estamos criando listas singleton com os dois componentes usando pure, fundindo-os juntos com <>, em seguida, transposeing esta "lista de listas" para obter os elementos devidamente intercalados e concating o resultado.