Este ejemplo funciona con ghci, cargue este archivo:

import Safe

t1 = tailMay []

Y poner en ghci:

> print t1
Nothing

Pero si agregamos una definición análoga al archivo anterior, no funciona:

import Safe

t1 = tailMay []
t2 = print $ tailMay []

Con tal error:

    * Ambiguous type variable `a0' arising from a use of `print'
      prevents the constraint `(Show a0)' from being solved.
      Probable fix: use a type annotation to specify what `a0' should be.
      These potential instances exist:
        instance Show Ordering -- Defined in `GHC.Show'
        instance Show Integer -- Defined in `GHC.Show'
        instance Show a => Show (Maybe a) -- Defined in `GHC.Show'
        ...plus 22 others

Esa es la tercera muestra para ghc con el mismo error:

import Safe

t1 = tailMay

main = do
  print $ t1 []
  print $ t1 [1,2,3]

¿Por qué? ¿Y cómo arreglar la segunda muestra sin una anotación de tipo explícita?

0
Vladimir 30 ago. 2020 a las 07:27

1 respuesta

La mejor respuesta

El problema aquí es que tailMay [] puede generar una salida de tipo Maybe [a] para cualquier a, mientras que print puede tomar una entrada de tipo Maybe [a] para cualquier a (en clase Show).

Cuando se compone un "productor universal" y un "consumidor universal", el compilador no tiene idea de qué tipo a elegir, que podría ser cualquier tipo de la clase Show. La elección de a podría importar ya que, en principio, print (Nothing :: Maybe [Int]) podría imprimir algo diferente de print (Nothing :: Maybe [Bool]). En este caso, la salida impresa sería la misma, pero solo porque tenemos suerte.

Por ejemplo, print ([] :: [Int]) y print ([] :: [Char]) imprimirán mensajes diferentes, por lo que print [] es ambiguo. Por lo tanto, GHC lo rechaza y requiere una anotación de tipo explícita (o una aplicación de tipo @ type, usando una extensión).

Entonces, ¿por qué se acepta tal ambigüedad en GHCi? Bueno, GHCi está destinado a ser utilizado para experimentos rápidos y, como tal, como una función de conveniencia, se esforzará por predeterminar estos a ambiguos. Esto se hace usando el reglas de incumplimiento extendidas, que podrían (supongo) en principio activarse en GHC también activando esa extensión. Sin embargo, esto no se recomienda ya que a veces la regla predeterminada puede elegir algún tipo no deseado, lo que hace que el código se compile pero con un comportamiento de tiempo de ejecución no deseado.

La solución común a este problema es usar una anotación (o @ type), porque proporciona más control al programador, hace que el código sea más fácil de leer y evita sorpresas.

3
chi 30 ago. 2020 a las 06:46