O Mundo Real Haskell, capítulo 4, página 98 da impressão pergunta se words
pode ser implementado usando dobras, e esta é minha pergunta também:
É possível? Se não, por que? Se for, como?
Eu vim com o seguinte, que é baseado na ideia de que cada não-espaço deve ser anexado à última palavra na lista de saída (isso acontece no otherwise
guarda) e que um espaço deve acionar o acréscimo de uma palavra vazia ao a lista de saída, se ainda não houver uma (isso é tratado no if
- then
- else
).
myWords :: String -> [String]
myWords = foldr step [[]]
where
step x yss@(y:ys)
| x == ' ' = if y == "" then yss else "":yss
| otherwise = (x:y):ys
Claramente, esta solução está errada, uma vez que os espaços iniciais na cadeia de entrada resultam em uma cadeia vazia principal na lista de cadeias de saída.
No link acima, examinei várias das soluções propostas para outros leitores, e muitas delas funcionam de forma semelhante à minha solução, mas geralmente "pós-processam" a saída da dobra, por exemplo tail
, se houver é uma string inicial vazia.
Outras abordagens usam tuplas (na verdade, apenas pares), para que a dobra lide com o par e possa lidar com os espaços iniciais / finais.
Em todas essas abordagens, foldr
(ou outra dobra, fwiw) não é a função que fornece a saída final pronta para uso; sempre há algo mais para ajustar a saída de alguma forma.
Portanto, volto à pergunta inicial e pergunto se é realmente possível implementar words
(de uma maneira que ele lide corretamente com espaços à direita / à esquerda / repetidos) usando dobras. Por usando pregas que significa que a função de dobragem tem de ser o mais exterior função:
myWords :: String -> [String]
myWords input = foldr step seed input
fonte
["xa"] == words "xa" == step 'x' (words "a") == step 'x' (words " a") == words "x a" == ["x", "a"]
, que tem o benefício de ser um argumento válido para qualquer direção da dobraO @chi possui um argumento maravilhoso que você não pode implementar
words
usando a dobra "a", mas você disse usando a dobra s .Tanto a função mais externa quanto a mais interna são dobras. ;-)
fonte
Sim. Mesmo que seja um pouco complicado, você ainda pode fazer esse trabalho corretamente usando um único
foldr
e mais nada se usar o CPS ( Continuation Passing Style ). Eu já havia mostrado um tipo especial dechunksOf
função anteriormente.Nesse tipo de dobra, nosso acumulador, portanto, o resultado da dobra é uma função e precisamos aplicá-lo a um tipo de entrada de identidade, para que tenhamos o resultado final. Portanto, isso pode contar como um estágio final de processamento ou não, pois estamos usando uma dobra única aqui e o tipo inclui a função. Aberto ao debate :)
sf
: O valor inicial da função para começar.go
: A função do iteradorNa verdade, não estamos utilizando totalmente o poder do CPS aqui, já que temos o personagem anterior
pc
e o personagem atualc
em cada turno. Foi muito útil nachunksOf
função mencionada acima, enquanto Arrancamento um[Int]
em[[Int]]
cada vez que uma sequência ascendente de elementos foram quebrados.fonte