La respuesta hasta ahora es engañosa.
Es necesario hacer una distinción entre polimorfismo "paramétrico" y "sobrecarga ad-hoc". Paramétrico significa "se comporta de manera uniforme para todos los tipos a", mientras que "ad-hoc", a lo que Simon se refiere como polimórfico, cambia la implementación en función del tipo.
Ejemplos de ambos son reverse :: [a] -> [a]
, que es paramétrico y show :: Show a => a -> String
que está "ad-hoc" sobrecargado.
Si desea una intuición más abstracta, creo que es útil considerar las clases de verbos del lenguaje natural que "funcionan" para todos los objetos, como "poseer" o "pensar" que no imponen restricciones al objeto, pero " abrir "requiere que de lo que estamos hablando se pueda abrir. Puedo "pensar en una puerta" y "abrir una puerta", mientras que no tiene sentido, por ejemplo, "abrir un árbol". Tomar el ejemplo aún más "abrir" es "polimórfico ad-hoc" como "abrir una ventana" y "abrir un ticket de queja con el servicio al cliente" son dos cosas muy diferentes. Si esto parece forzado, ¡olvídalo! Esto funciona para mi.
Sin embargo, ambos se resuelven en tiempo de compilación y de hecho se "borran". Modulo de varias extensiones de GHC y Template Haskell, etc. De hecho , los tipos se borran en tiempo de compilación y nunca se inspeccionan en tiempo de ejecución.
Las funciones polimórficas paramétricas se comportan de manera idéntica para todos los tipos, por lo que solo se debe generar una pieza de código, mientras que el compilador decide en el momento de la compilación qué versión de una función "clasificada por tipo" debe ejecutarse en un punto de programa particular. Esta es también la razón por la cual existe la restricción de una instancia por tipo por clase de tipo y la solución alternativa "newtype" correspondiente.
La implementación se detalla en el libro de texto de SPJ y el documento de Wadler y Blotts sobre clases de tipos .
a -> String
. Lo más probable es que tenga una restricción de tipo, comoShow a => a -> String
.