tipos tag sobre significado para llaman letras hay graffitis graffiti formas ejemplos cuantos como clases bombing haskell

haskell - sobre - tag para graffiti



¿Cuál es una buena razón para usar una firma de tipo para funciones cuando el compilador puede inferir los tipos? (4)

Estoy tratando de codificar usando el "buen estilo Haskell" y por eso trato de seguir los estándares de codificación típicos que encuentro. Además, compilar con -Wall y -Werror como estoy acostumbrado cuando vengo de C. Una de las advertencias que recibo con frecuencia es "Enlace de nivel superior sin firma de tipo" y luego el compilador me dice cuál debe ser la firma de tipo.

Me estoy perdiendo cuál es la ventaja de tener la firma de tipo definida explícitamente. Como ejemplo concreto:

-- matchStr :: String -> String -> Maybe (String) matchStr str s | isPrefixOf str s = Just(drop (length str) s) | otherwise = Nothing

Ahora, ¿qué sucede si deseo cambiar el tipo de String a ByteString para mejorar el rendimiento? Tendré que importar el paquete ByteString y usar una versión calificada de algunas funciones. No son necesarios otros cambios. Si tengo la firma de tipo, también tengo que cambiar esto y, sin embargo, el compilador de Haskell notará este cambio e inferirá correctamente los nuevos tipos.

Entonces, ¿qué me estoy perdiendo? ¿Por qué se considera una buena idea poner explícitamente firmas de tipo en funciones en el caso general? es decir, entiendo que puede haber excepciones donde sea una buena idea, pero ¿por qué se considera buena en general?


Consideraría la documentación como una ventaja de tener una firma de tipo explícita.

De "Tipos y lenguajes de programación":

Los tipos también son útiles al leer programas. Las declaraciones de tipo en los encabezados de los procedimientos y las interfaces de los módulos constituyen una forma de documentación, que proporciona sugerencias útiles sobre el comportamiento. Además, a diferencia de las descripciones integradas en los comentarios, esta forma de documentación no puede quedar desactualizada, ya que se verifica durante cada ejecución del compilador. Este rol de los tipos es particularmente importante en las firmas de módulos.


Hay varias razones.

  1. Puede hacer que el código sea más fácil de leer para los humanos. (OTOH, si tiene docenas de pequeñas definiciones, a veces las firmas de tipo agregan más desorden).
  2. Si su implementación es incorrecta, el compilador puede inferir el tipo incorrecto. Esto puede hacer que los tipos de otras funciones se deduzcan mal, lo que finalmente da como resultado un error de tipo muy alejado de la función interrumpida real.
  3. Es posible que desee asignar a una función un tipo menos polimórfico del que podría tener, por motivos de rendimiento.
  4. Es posible que desee utilizar alias de tipo. Esto le permite cambiar rápidamente un tipo en varios lugares y también documentar parte de la intención detrás de un valor. (Compare FilePath vs String .)
  5. El compilador puede descubrir tipos automáticamente, pero no todas las herramientas externas pueden hacer esto. (Por ejemplo, originalmente Haddock se negaría a producir documentación para funciones que carezcan de una firma de tipo explícita, aunque supongo que esto ya está solucionado).

Vale la pena señalar que algunas personas abogan por comenzar con las firmas de tipo y completar las implementaciones más adelante.

En cualquier caso, la mayoría de las personas parecen recomendar firmas de tipo para todas o la mayoría de las declaraciones de nivel superior . Si los das para las funciones / variables locales es cuestión de gustos.


Si comete un error al definir su función, el compilador podría inferir un tipo que no es el que esperaba. Si ha declarado el tipo que espera, el compilador informará el error en la definición de la función.

Sin la declaración, el compilador no tiene manera de saber que su tipo inferido es "incorrecto", y en su lugar terminará reportando errores en los lugares donde intenta llamar a la función, lo que hace que sea menos claro dónde está el problema.

Si las funciones de llamada tampoco tienen declaraciones de tipo, entonces, en lugar de reportar errores allí, el compilador podría inferir tipos incorrectos para ellos también, causando problemas en las personas que llaman. Terminará obteniendo un mensaje de error en algún lugar , pero puede estar bastante lejos de la raíz real del problema.

Además, puede declarar un tipo más específico de lo que inferiría el compilador. Por ejemplo, si escribes la función:

foo n = n + 1

El compilador deducirá el tipo Num a => a -> a , lo que significa que debe compilar código genérico que pueda funcionar con cualquier instancia de Num . Si declara el tipo como Int -> Int , el compilador puede ser capaz de producir un código más eficiente que esté especializado solo para enteros.

Finalmente, las declaraciones de tipo sirven como documentación. El compilador puede inferir los tipos de expresiones complejas, pero no es tan fácil para un lector humano. Una declaración de tipo proporciona la "imagen general" que puede ayudar a un programador a comprender qué hace la función.

Tenga en cuenta que los comentarios de Haddock se adjuntan a las declaraciones, no a las definiciones. Escribir una declaración de tipo es el primer paso para proporcionar documentación adicional para una función que utiliza Haddock.


Su ejemplo artificial es realmente artificial, ya que el cuerpo de la función no depende del tipo de contenido de la lista. En este caso, es realmente difícil ver cuál es el beneficio de definir el tipo a ser [String] -> ([String],[String]) lugar de [a]->([a],[a])

Si intenta definir una función que depende de los contenidos, verá que la definición de tipo no es lo único que necesita cambiar. Por ejemplo, cambiar una lista para MArray va a ser mucho más complicado, no solo usando una función que tenga el mismo nombre en un módulo diferente. Por lo tanto, calificar el nombre durante la refactorización en unos pocos casos limitados no es una razón suficiente para no especificar firmas de tipo.

Especificar el tipo le dice al compilador un poco de la intención. Luego, el compilador podrá reportar el desajuste de la intención y la implementación.