C # , Scala, Haskell, Lisp et Python ont le même zip
comportement: si une collection est plus longue, la queue est silencieusement ignorée.
Cela pourrait également être une exception, mais je n'ai entendu parler d'aucun langage utilisant cette approche.
Cela me laisse perplexe. Quelqu'un connaît-il la raison pour laquelle il zip
est conçu de cette façon? Je suppose que pour les nouvelles langues, cela se fait parce que d'autres langues le font de cette façon. Mais quelle était la raison profonde?
Je pose ici une question factuelle et historique, pas si quelqu'un l'aime, ou si c'est une bonne ou une mauvaise approche.
Mise à jour : si on me demandait quoi faire, je dirais - lever une exception, de manière assez similaire à l'indexation d'un tableau (malgré les "anciennes" langues qui faisaient toute sorte de magie, comment gérer l'index hors limites, UB, étendre le tableau, etc).
la source
zipWithIndex
fournissant un générateur de nombres naturels. Maintenant, ne manque plus que morceau de info - ce qui était elle la raison? :-) (btw. veuillez republier votre commentaire comme réponse, merci).Réponses:
C'est presque toujours ce que vous voulez, et quand ce n'est pas le cas, vous pouvez faire le plein vous-même.
Le problème principal est qu'avec la sémantique paresseuse, vous ne connaissez pas la longueur lorsque vous démarrez le
zip
, donc vous ne pouvez pas simplement lever une exception au début. Vous devez d'abord renvoyer tous les éléments communs, puis lever une exception, ce qui ne serait pas très utile.C'est aussi un problème de style. Les programmeurs impératifs sont habitués à vérifier manuellement les conditions aux limites partout. Les programmeurs fonctionnels préfèrent les constructions qui ne peuvent pas échouer par conception. Les exceptions sont extrêmement rares. S'il existe un moyen pour une fonction de renvoyer une valeur par défaut raisonnable, les programmeurs fonctionnels la prendront. La composabilité est reine.
la source
zip
est actuellement mis en œuvre. Lancer une exception consiste simplement à remplacer «stop yield» par «throw». Troisième paragraphe - renvoyer un élément vide pour atteindre hors de la frontière ne peut pas échouer, mais je doute que tout développeur FP voterait que c'est une bonne conception.zip
deux séquences infinies ensemble, vous ne connaissez pas la taille au début. Au troisième paragraphe, j'ai dit défaut raisonnable . Retourner vide dans ce cas ne serait pas raisonnable, alors que laisser tomber la queue l'est évidemment.Parce qu'il n'y a aucun moyen évident de terminer la queue. Tout choix sur la façon de le faire entraînerait une queue non évidente.
L'astuce consiste à allonger explicitement votre liste la plus courte pour faire correspondre la longueur de la plus longue aux valeurs que vous attendez.
Si zip l'a fait pour vous, vous ne pouviez pas savoir quelles valeurs il remplissait intuitivement. At-il parcouru la liste? At-il répété une valeur vide? Quelle est une valeur vide pour votre type?
Il n'y a aucune implication dans ce que fait zip que l'on pourrait utiliser pour comprendre la façon dont la queue serait allongée, donc la seule chose raisonnable à faire est de travailler avec les valeurs disponibles plutôt que d'en inventer certaines auxquelles votre consommateur ne peut pas s'attendre.
Souvenez-vous également que vous faites référence à une fonction bien connue très spécifique avec une sémantique bien connue. Mais cela ne signifie pas que vous ne pouvez pas créer une fonction similaire mais légèrement différente . Ce
x
n'est pas parce qu'il y a une fonction commune que vous ne pouvez pas décider pour quel objectif vous voulez fairex
ety
.Bien que vous vous souveniez de la raison pour laquelle cela et de nombreuses autres fonctions de style FP communes sont courantes, c'est parce qu'elles sont simples et généralisées afin que vous puissiez modifier votre code pour les utiliser et obtenir le comportement que vous souhaitez. Par exemple, en C #, vous pouvez simplement
Ou d'autres choses simples. Les approches FP rendent les modifications si faciles car vous pouvez réutiliser des pièces et avoir des implémentations aussi petites que ci-dessus que créer vos propres versions modifiées des choses est extrêmement simple.
la source
zip
pourrait remplir des valeurs nulles, ce qui est souvent une solution intuitive. Tenez compte du typezip :: [a] -> [b] -> [(Maybe a, Maybe b)]
. Certes, le type de résultat est un peu ^ H ^ H assez peu pratique, mais il permettrait d'implémenter facilement tout autre comportement (raccourci, exception) par-dessus.mempty
, les objets ont une valeur nulle pour remplir l'espace, mais vous voulez qu'il ait une telle chose pour les types int et autres? Bien sûr, C # adefault(T)
mais pas tous les langages, et même pour C # est-ce vraiment un comportement évident ? Je ne pense pas