GHCi忽略了类型签名

Mat*_*hid 20 haskell ghci

Prelude> let myprint = putStrLn . show
Prelude> :t myprint
myprint :: () -> IO ()
Run Code Online (Sandbox Code Playgroud)

好的,这里没什么不寻常的.只是GHCi类型的默认规则,我猜......

Prelude> let myprint = (putStrLn . show) :: Show x => x -> IO ()
Prelude> :t myprint
myprint :: () -> IO ()
Run Code Online (Sandbox Code Playgroud)

这是什么巫术?你是无意识的,忽略了我的类型声明?!O_O

有什么方法可以说服GHCi做我真正的意图吗?

chi*_*chi 21

表达式注释添加到表达式中,

e :: type
Run Code Online (Sandbox Code Playgroud)

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

(id :: a -> a) "hello"
Run Code Online (Sandbox Code Playgroud)

尽管我的注释,上面a将被实例化String.进一步,

foo :: Int -> Int
foo = (id :: a -> a)
Run Code Online (Sandbox Code Playgroud)

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

同样,表达式

putStrLn . show
Run Code Online (Sandbox Code Playgroud)

(putStrLn . show) :: Show x => x -> IO ()
Run Code Online (Sandbox Code Playgroud)

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

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

myprint :: Show x => x -> IO ()
myprint = (putStrLn . show)
Run Code Online (Sandbox Code Playgroud)


And*_*ács 17

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

>let myprint :: Show x => x -> IO (); myprint = putStrLn . show
>:t myprint
myprint :: Show x => x -> IO ()
Run Code Online (Sandbox Code Playgroud)

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