plataforma - haskell website
GHCi ignora la firma del tipo (2)
Prelude> let myprint = putStrLn . show
Prelude> :t myprint
myprint :: () -> IO ()
OK, nada demasiado inusual aquí. Solo las reglas predeterminadas de tipo GHCi, supongo ...
Prelude> let myprint = (putStrLn . show) :: Show x => x -> IO ()
Prelude> :t myprint
myprint :: () -> IO ()
¿¿Que brujería es esta?? ¿Estás en un punto en blanco ignorando mi declaración de tipo? O_O
¿Hay alguna manera de convencer a GHCi para que haga lo que realmente quería?
Agregar una anotación de tipo a una expresión como en
e :: type
hace que el compilador compruebe que e
tiene ese type
, así como el uso de ese type
para impulsar la creación de instancias de variables de tipo y la selección de instancias. Sin embargo , si el type
es polimórfico, aún se puede crear una instancia más adelante. Considerar por ejemplo
(id :: a -> a) "hello"
Anteriormente, se creará una instancia de String
, a pesar de mi anotación. Promover,
foo :: Int -> Int
foo = (id :: a -> a)
hará a
instancia para ser instanciada a Int
más adelante. La anotación anterior de id
no da ninguna información a GHC: ya sabe que id
tiene ese tipo. Podríamos eliminarlo sin afectar la comprobación de tipo en absoluto. Es decir, las expresiones id
e id :: a->a
no solo son dinámicamente equivalentes, sino también estáticamente similares.
Del mismo modo, las expresiones.
putStrLn . show
y
(putStrLn . show) :: Show x => x -> IO ()
son estáticamente equivalentes: solo estamos anotando el código con el tipo que GHC puede inferir. En otras palabras, no estamos proporcionando ninguna información a GHC que aún no conozca.
Una vez que se verifica el tipo de anotación, GHC puede crear una instancia de x
más. La restricción de monomorfismo hace eso en tu ejemplo. Para evitar eso, use una anotación para el enlace que está introduciendo, no para la expresión :
myprint :: Show x => x -> IO ()
myprint = (putStrLn . show)
Podemos hacer lo siguiente, con restricción de monomorfismo en:
>let myprint :: Show x => x -> IO (); myprint = putStrLn . show
>:t myprint
myprint :: Show x => x -> IO ()
Esto no es lo mismo que let myprint = putStrLn . show :: Show x => x -> IO ()
let myprint = putStrLn . show :: Show x => x -> IO ()
. En el primer caso tenemos un enlace con una firma de tipo, en el último caso tenemos un enlace con una anotación de tipo en el lado derecho. El monomorfismo verifica las firmas de tipo de nivel superior, pero no las anotaciones locales.