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具有该类型.我们可以删除它而不会影响类型检查.也就是说,表达式id和id :: 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在右侧有一个带有类型注释的绑定.单态检查顶级类型签名,但不检查本地注释.