¿Por qué la `cabeza` de Haskell se cuelga en una lista vacía (o por qué * no * devuelve una lista vacía)? (Filosofía del lenguaje)

Nota para otros contribuyentes potenciales: no dude en usar anotaciones abstractas o matemáticas para expresar su punto. Si encuentro que su respuesta no está clara, pediré aclaraciones, pero de lo contrario, siéntase libre de expresarse de una manera cómoda.

Para ser claros: soyn buscando un "seguro"head, ni es la elección dehead en particular excepcionalmente significativo. La carne de la pregunta sigue a la discusión dehead yhead', que sirven para proporcionar contexto.

He estado pirateando con Haskell durante unos meses (hasta el punto de que se ha convertido en mi idioma principal), pero ciertamente no estoy bien informado sobre algunos de los conceptos más avanzados ni los detalles de la filosofía del idioma ( aunque estoy más que dispuesto a aprender). Mi pregunta no es tanto técnica (a menos que lo sea y simplemente no me doy cuenta), sino de filosofía.

Para este ejemplo, estoy hablando dehead.

Como imagino que sabrás,

Prelude> head []    
*** Exception: Prelude.head: empty list

Esto se desprende dehead :: [a] -> a. Lo suficientemente justo. Obviamente, uno no puede devolver un elemento de (sin agitar la mano) ningún tipo. Pero al mismo tiempo, es simple (si no trivial) definir

head' :: [a] -> Maybe a
head' []     = Nothing
head' (x:xs) = Just x

He visto algunas pequeñas discusiones sobre estoaqu en la sección de comentarios de ciertas declaraciones. En particular, un Alex Stangl dice

'Hay buenas razones para no hacer que todo sea "seguro" y lanzar excepciones cuando se violan las condiciones previas.'

o cuestiono necesariamente esta afirmación, pero tengo curiosidad sobre cuáles son estas "buenas razones".

Además, un Paul Johnson dice:

'Por ejemplo, podría definir "safeHead :: [a] -> Quizás a", pero ahora, en lugar de manejar una lista vacía o demostrar que no puede suceder, debe manejar "Nada" o demostrar que no puede ocurrir.'

El tono que leí de ese comentario sugiere que este es un aumento notable en la dificultad / complejidad / algo, pero no estoy seguro de comprender lo que está publicando allí.

Uno Steven Pruzina dice (en 2011, nada menos),

"Hay una razón más profunda por la cual, por ejemplo, 'head' no puede ser a prueba de choques. Para ser polimórfico y manejar una lista vacía, 'head' siempre debe devolver una variable del tipo que está ausente de cualquier lista vacía en particular. sé Delphic si Haskell pudiera hacer eso ... ".

¿Se pierde el polimorfismo al permitir el manejo de listas vacías? Si es así, ¿cómo y por qué? ¿Hay casos particulares que lo harían obvio? @Esta sección respondió ampliamente por @Russell O'Connor. Cualquier otro pensamiento es, por supuesto, apreciado.

Editaré esto como lo indique la claridad y la sugerencia. Cualquier comentario, documentación, etc. que pueda proporcionar será muy apreciado.

Respuestas a la pregunta(6)

Su respuesta a la pregunta