C # , Scala, Haskell, Lisp y Python tienen el mismo zip
comportamiento: si una colección es más larga, la cola se ignora en silencio.
También podría ser una excepción, pero no escuché ningún lenguaje usando este enfoque.
Esto me desconcierta. ¿Alguien sabe la razón por la cual zip
está diseñado de esa manera? Supongo que para los nuevos idiomas, se hace porque otros idiomas lo hacen de esta manera. Pero, ¿cuál fue la razón raíz?
Estoy haciendo una pregunta basada en hechos históricos, no si a alguien le gusta o si es un enfoque bueno o malo.
Actualización : si me preguntaran qué hacer, diría: arroje una excepción, de manera muy similar a indexar una matriz (a pesar de que los idiomas "antiguos" hicieron todo tipo de magia, cómo manejar el índice fuera de límites, UB, expandir matriz, etc)
fuente
zipWithIndex
natural proporcionando un generador de números naturales. Ahora, la pieza única que falta de información - lo que era que la razón? :-) (por cierto, vuelve a publicar tu comentario como respuesta, gracias).Respuestas:
Casi siempre es lo que desea, y cuando no lo es, puede hacerlo usted mismo.
El problema principal es con la semántica perezosa que no conoce la longitud cuando inicia por primera vez
zip
, por lo que no puede lanzar una excepción al comienzo. Debería devolver primero todos los elementos comunes, luego lanzar una excepción, que no sería muy útil.También es un problema de estilo. Los programadores imperativos están acostumbrados a verificar manualmente las condiciones de contorno en todo el lugar. Los programadores funcionales prefieren construcciones que no pueden fallar por diseño. Las excepciones son extremadamente raras. Si hay una manera para que una función devuelva un valor predeterminado razonable, los programadores funcionales lo tomarán. La componibilidad es el rey.
fuente
zip
se implementa actualmente. Lanzar una excepción es simplemente cambiar "detener el rendimiento" a "lanzar". Tercer párrafo: devolver el elemento vacío para llegar fuera del límite no puede fallar, pero dudo que cualquier desarrollador de FP vote que sea un buen diseño.zip
dos secuencias infinitas juntas, no sabes el tamaño al principio. En el tercer párrafo, dije incumplimiento razonable . Volver vacío en este caso no sería razonable, mientras que dejar caer la cola obviamente lo es.Porque no hay una forma obvia de completar la cola. Cualquier elección sobre cómo hacerlo daría como resultado una cola no obvia.
El truco es alargar explícitamente su lista más corta para que coincida con la longitud de la más larga con los valores que espera.
Si zip lo hiciera por usted, no podría saber qué valores estaba completando intuitivamente. ¿Ciclo la lista? ¿Repitió un valor mempty? ¿Cuál es un valor mempty para tu tipo?
No hay ninguna implicación en lo que hace zip que uno podría usar para intuir la forma en que se alargaría la cola, por lo que lo único razonable es trabajar con los valores disponibles en lugar de inventar algo que su consumidor no puede esperar.
También recuerde que se refiere a una función conocida muy específica con una semántica bien conocida específica. Pero eso no significa que no pueda hacer una función similar pero ligeramente diferente . El hecho de que hay una función común que hace
x
, no significa que no se puede decidir para su propósito dado que quiere hacerx
yy
.Aunque recuerde que esta y muchas otras funciones comunes de estilo FP son comunes, es porque son simples y generalizadas para que pueda modificar su código para usarlas y obtener el comportamiento que desea. Por ejemplo, en C # podrías simplemente
U otras cosas simples. Los enfoques de FP hacen que las modificaciones sean tan fáciles porque puede reutilizar piezas y tener implementaciones tan pequeñas como las anteriores para que crear sus propias versiones modificadas de cosas sea extremadamente simple.
fuente
zip
podría completar nulos, que a menudo es una solución intuitiva. Considera el tipozip :: [a] -> [b] -> [(Maybe a, Maybe b)]
. Por supuesto, el tipo de resultado es un poco ^ H ^ H bastante poco práctico, pero permitiría implementar fácilmente cualquier otro comportamiento (atajo, excepción) encima.mempty
objetos tienen un valor nulo para llenar el espacio, pero ¿quieres que tenga que tener algo así para int y otros tipos también? Claro, C # tienedefault(T)
pero no todos los lenguajes lo hacen, e incluso para C # ¿es ese comportamiento realmente obvio ? No lo creo