Renderizando valores em itens e itens intermediários em Haskell

Dec 21 2020

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

3 DDub Dec 21 2020 at 06:11

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.