GHCi忽略了类型签名

时间:2015-03-22 10:38:02

标签: haskell ghci

Prelude> let myprint = putStrLn . show
Prelude> :t myprint
myprint :: () -> IO ()
好的,这里没什么不寻常的。只是GHCi类型的默认规则,我猜......

Prelude> let myprint = (putStrLn . show) :: Show x => x -> IO ()
Prelude> :t myprint
myprint :: () -> IO ()

这是什么巫术?你是直言忽略我的类型声明?! O_O

有什么方法可以说服GHCi做我真正想要的事情吗?

2 个答案:

答案 0 :(得分:21)

表达式中添加类型注释,如

e :: type

使编译器检查e是否具有type,以及使用type来驱动类型变量实例化和实例选择。 然而,如果type是多态的,它仍然可以在以后实例化。考虑例如。

(id :: a -> a) "hello"

上面,a将被实例化为String,尽管我的注释。此外,

foo :: Int -> Int
foo = (id :: a -> a)

稍后会将a实例化为Int。上面的id注释没有向GHC提供任何信息:它已经知道id具有该类型。 我们可以删除它而不会影响类型检查。也就是说,表达式idid :: a->a不仅是动态等效的,而且也是静态等效的。

同样,表达式

putStrLn . show

(putStrLn . show) :: Show x => x -> IO ()

是静态等价的:我们只是用GHC可以推断的类型来注释代码。换句话说,我们没有向GHC提供任何尚未了解的信息。

在注释类型检查后,GHC可以进一步实例化x。在您的示例中,单态限制就是这样。为防止这种情况,请使用您正在介绍的绑定的注释,而不是表达式

myprint :: Show x => x -> IO ()
myprint = (putStrLn . show)

答案 1 :(得分:17)

我们可以执行以下操作,单一性限制:

>let myprint :: Show x => x -> IO (); myprint = putStrLn . show
>:t myprint
myprint :: Show x => x -> IO ()

这与let myprint = putStrLn . show :: Show x => x -> IO ()不同。在前一种情况下,我们有一个带有类型签名的绑定,在后一种情况下,我们在右侧有一个带有类型注释的let绑定。单态检查顶级类型签名,但不检查本地注释。