C # , Scala, Haskell, Lisp e Python têm o mesmo zip
comportamento: se uma coleção for maior, a cauda será ignorada silenciosamente.
Também poderia ser uma exceção, mas não ouvi nenhum idioma usando essa abordagem.
Isso me intriga. Alguém sabe o motivo pelo qual zip
é projetado dessa maneira? Eu acho que para novos idiomas, isso é feito porque outros idiomas fazem dessa maneira. Mas qual foi o principal motivo?
Estou fazendo aqui uma pergunta factual e histórica, não se alguém gosta, ou se é uma abordagem boa ou ruim.
Atualização : se me perguntassem o que fazer, eu diria - lance uma exceção, de maneira semelhante à indexação de uma matriz (apesar de linguagens "antigas" fazerem todo tipo de mágica, como lidar com índices fora dos limites, UB, expandir matriz, etc).
fonte
zipWithIndex
fornecimento de gerador de números naturais. Agora, a peça faltando apenas de informação - o que era ele o motivo? :-) (btw. por favor, repense seu comentário como resposta, obrigado).Respostas:
É quase sempre o que você deseja e, quando não é, pode fazer o preenchimento sozinho.
O principal problema é com a semântica preguiçosa que você não sabe o tamanho quando inicia o primeiro
zip
, portanto não pode simplesmente lançar uma exceção no início. Você precisaria primeiro retornar todos os elementos comuns e depois lançar uma exceção, o que não seria muito útil.Também é uma questão de estilo. Programadores imperativos estão acostumados a verificar manualmente as condições de contorno em todo o lugar. Programadores funcionais preferem construções que não podem falhar por design. Exceções são extremamente raras. Se houver uma maneira de uma função retornar um padrão razoável, os programadores funcionais a aceitarão. Composability é rei.
fonte
zip
é implementado atualmente. A exceção de lançamento é simplesmente alterar "stop yield" para "throw". Terceiro parágrafo - retornar um elemento vazio para alcançar fora dos limites não pode falhar, mas, no entanto, duvido que qualquer desenvolvedor de FP votaria como um bom design.zip
duas sequências infinitas juntas, não sabe o tamanho no início. No terceiro parágrafo, eu disse padrão razoável . Retornar vazio neste caso não seria razoável, ao passo que deixar cair o rabo obviamente é.Porque não há uma maneira óbvia de completar a cauda. Qualquer escolha sobre como fazê-lo resultaria em uma cauda não óbvia.
O truque é aumentar explicitamente sua lista mais curta para corresponder à duração da maior com os valores esperados.
Se o zip fez isso por você, você não sabia quais valores estavam preenchendo intuitivamente. Ciclou a lista? Repetiu um valor de mempty? O que é um valor de mempty para o seu tipo?
Não há nenhuma implicação no que o zip faz que alguém poderia usar para intuir a maneira como a cauda seria alongada; portanto, a única coisa razoável a fazer é trabalhar com os valores disponíveis, em vez de criar alguns que o consumidor não pode esperar.
Lembre-se também de que você está se referindo a uma função conhecida muito específica com semântica específica conhecida. Mas isso não significa que você não pode fazer uma função semelhante, mas um pouco diferente . Só porque existe uma função comum que faz isso
x
, não significa que você não pode decidir para o propósito que deseja fazerx
ey
.Embora lembre-se do motivo pelo qual essas e muitas outras funções comuns do estilo FP são comuns, é porque elas são simples e generalizadas, para que você possa ajustar seu código para usá-las e obter o comportamento desejado. Por exemplo, em C # você poderia apenas
Ou outras coisas simples. As abordagens de FP tornam as modificações muito fáceis, porque você pode reutilizar peças e ter implementações tão pequenas quanto acima, que criar suas próprias versões modificadas das coisas é extremamente simples.
fonte
zip
poderia preencher nulos, o que geralmente é uma solução intuitiva. Considere o tipozip :: [a] -> [b] -> [(Maybe a, Maybe b)]
. É verdade que o tipo de resultado é um pouco ^ H ^ H bastante impraticável, mas permitiria implementar facilmente qualquer outro comportamento (atalho, exceção) em cima dele.mempty
, os objetos têm nulo para preencher o espaço, mas você quer que ele tenha que criar uma coisa dessas para int e outros tipos também? Claro, o C # possui,default(T)
mas nem todos os idiomas, e mesmo para o C # esse comportamento é realmente óbvio ? Acho que não