online - haskell pdf
ImplementaciĆ³n de la funciĆ³n nula. (3)
Tengo que aprender Haskell para la universidad y por eso estoy usando learnyouahaskell.com para el comienzo.
Siempre usé lenguajes imperativos, así que decidí practicar Haskell codificando mucho más de lo que lo haría para otros idiomas.
Comencé a implementar varias funciones para trabajar con listas como head
, tail
, init
, ...
En algún momento busqué las implementaciones de estas funciones para compararlas con las mías y me topé con la función nula definida en List.lhs
.
implementación nula:
-- | Test whether a list is empty.
null :: [a] -> Bool
null [] = True
null (_:_) = False
mi implementación:
mNull :: [a] -> Bool
mNull [] = True
mNull _ = False
Sé que no hay preguntas estúpidas, incluso para preguntas tan simples :)
Entonces, mi pregunta es ¿por qué la implementación original usa (_:_)
lugar de solo _
?
¿Hay alguna ventaja en el uso de (_:_)
o hay algún caso límite que no conozca?
Realmente no puedo imaginar ninguna ventaja porque _
atrapa todo.
No puedes simplemente cambiar las cláusulas con tu solución:
mNull'' :: [a] -> Bool
mNull'' _ = False
mNull'' [] = True
esto siempre dará como resultado False
, incluso si pasa una lista vacía. Debido a que el tiempo de ejecución nunca considera la cláusula []
, inmediatamente ve _
coincide con cualquier cosa. (GHC le advertirá sobre este patrón superpuesto).
Por otra parte,
null'' :: [a] -> Bool
null'' (_:_) = False
null'' [] = True
sigue funcionando correctamente, porque (_:_)
no coincide con el caso particular de una lista vacía.
Eso en sí mismo no da realmente una ventaja a las dos cláusulas explícitas. Sin embargo, en un código más complicado, escribir todas las opciones de exclusión mutua tiene un beneficio: si ha olvidado una opción, el compilador también puede advertirle sobre eso. Considerando que un _
puede y solo manejará cualquier caso no tratado por las cláusulas anteriores, incluso si eso no es realmente correcto.
Porque _
literalmente significa cualquier cosa aparte de patrones explícitamente especificados. Cuando especifica (_:_)
significa cualquier cosa que pueda representarse como una lista que contenga al menos 1 elemento, sin preocuparse por qué o incluso cuántos elementos contiene realmente la lista. Dado que el caso con un patrón explícito para una lista vacía ya está presente, (_:_)
podría ser reemplazado por _
.
Sin embargo, representarlo como (_:_)
le brinda la flexibilidad de no pasar ni siquiera explícitamente el patrón de lista vacía. De hecho, esto funcionará:
-- | Test whether a list is empty.
null :: [a] -> Bool
null (_:_) = False
null _ = True
Voy a añadir a lo que dijo alrededor de la izquierda. Esto no es realmente una preocupación potencial para el tipo de lista, pero en general, los tipos de datos a veces se modifican. Si tienes un mal concebido
data FavoriteFood = Pizza
| SesameSpinachPancake
| ChanaMasala
y luego aprenderá a gustar DrunkenNoodles
y agregarlo a la lista, todas las funciones que coincidan con el patrón tendrán que expandirse. Si ha utilizado algún _
patrón, deberá buscarlo manualmente; El compilador no puede ayudarte. Si ha hecho coincidir cada cosa explícitamente, puede activar los -fwarn-incomplete-patterns
y GHC le informará sobre cada punto que haya perdido.