type length funcion haskell standard-library

length - funcion filter en haskell



¿Por qué las clases estándar de Haskell 98 fueron inferiores a las de Haskell 1.3? (1)

¿Por qué se cambiaron estas cosas para Haskell 98 y por qué de esta manera?

Haskell 98 implica mucha simplificación del lenguaje (gran parte de la cual ya se ha revertido). El objetivo era mejorar Haskell como lenguaje de enseñanza y tomar decisiones relativamente conservadoras.

Ver por ejemplo

Consideramos Haskell 98 como un diseño razonablemente conservador. Por ejemplo, en ese momento las clases de tipos de parámetros múltiples estaban siendo ampliamente utilizadas, pero Haskell 98 solo tiene clases de tipos de parámetros únicos (Peyton Jones et al., 1997).

En: Historia de Haskell

Y:

Haskell 98 no será de ninguna manera la última revisión de Haskell. Por el contrario, lo diseñamos sabiendo que las nuevas extensiones de lenguaje (clases de tipo de múltiples parámetros, cuantificación universal y existencial, protectores de patrones, etc, etc.) están en camino. Sin embargo, Haskell 98 tendrá un estado especial: la intención es que los compiladores de Haskell continúen admitiendo Haskell 98 (dado un indicador apropiado) incluso después de que se hayan definido versiones posteriores del lenguaje, por lo que el nombre "Haskell 98" se referirá a Un lenguaje fijo, estable.

En: informe Haskell98

Entonces, las cosas se simplificaron, con el objetivo de producir un estándar más simple.

Antes de Haskell 98, había Haskell 1.0 a 1.4. Es bastante interesante ver el desarrollo a lo largo de los años, ya que las funciones se agregaron a las primeras versiones de Haskell estandarizado.

Por ejemplo, la notación fue estandarizada por primera vez por Haskell 1.3 (publicada 1996-05-01). En el Prelude , encontramos las siguientes definiciones (página 87):

-- Monadic classes class Functor f where map :: (a -> b) -> f a -> f b class Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a m >> k = m >>= /_ -> k class (Monad m) => MonadZero m where zero :: m a class (MonadZero m) => MonadPlus m where (++) :: m a -> m a -> m a

Las mismas definiciones se encuentran en Haskell 1.4. Tengo algunos problemas con esto (por ejemplo, la reforma de MonadPlus no ha ocurrido aquí todavía), pero en general, es una muy buena definición.

Esto es muy diferente de Haskell 98, donde se encuentra la siguiente definición:

-- Monadic classes class Functor f where fmap :: (a -> b) -> f a -> f b class Monad m where (>>=) :: m a -> (a -> m b) -> m b (>>) :: m a -> m b -> m b return :: a -> m a fail :: String -> m a -- Minimal complete definition: -- (>>=), return m >> k = m >>= /_ -> k fail s = error s

Esta es también la definición en Haskell 2010. Tengo los siguientes problemas con esta definición:

  • MonadZero y MonadPlus se han ido. Eran clases útiles.
  • En caso de una falla de coincidencia de patrón en una do-notación ...

    • Haskell 1.3 usa zero . Se aplica la ley del Cero Izquierdo ( zero >>= k = zero ), para que sepa qué se supone que suceda.
    • Haskell 98 usa fail msg , donde msg es generado por el compilador en el caso de GHC. Cualquier cosa puede pasar, no hay garantías sobre su semántica. Por lo tanto, no es una gran función para los usuarios. Como consecuencia, el comportamiento de los fallos de coincidencia de patrón en la notación de Haskell 98 es impredecible.
  • Los nombres son menos generales (por ejemplo, map vs. fmap ). No es un gran problema, pero es una espina en mi ojo.

Con todo, creo que estos cambios no fueron para mejor. De hecho, creo que fueron un paso atrás de Haskell 1.4. ¿Por qué se cambiaron estas cosas para Haskell 98 y por qué de esta manera?

A un lado, puedo imaginar las siguientes defensas:

  • " fail permite localizar errores". Solo para programadores, y solo en tiempo de ejecución. El mensaje de error (¡unportable!) No es exactamente algo que desee analizar. Si realmente te importa, deberías seguirlo explícitamente. Ahora tenemos Control.Failure del paquete de failure , que hace un trabajo mucho mejor en esto (el failure x comporta principalmente como zero ).
  • "Tener demasiadas clases hace que el desarrollo y el uso sean demasiado difíciles". Tener muy pocas clases infringe sus leyes, y esas leyes son tan importantes como los tipos.
  • "Las funciones restringidas a instancias son más fáciles de aprender". Entonces, ¿por qué no hay un SimplePrelude en SimplePrelude lugar, con la mayoría de las clases eliminadas? Es solo una declaración mágica para los estudiantes, ellos pueden manejar eso. (Quizás también se necesita {-# LANGUAGE RebindableSyntax #-} , pero nuevamente, los estudiantes son muy buenos para copiar y pegar cosas).
  • "Las funciones restringidas de instancia hacen que los errores sean más legibles". Uso fmap mucho más a menudo que map , así que, ¿por qué no map y listMap en listMap lugar?