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做我真正想做的事吗?
发布于 2015-03-22 11:18:16
我们可以通过对以下方面的单形限制来完成以下工作:
>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绑定。单体主义检查顶级类型签名,但不检查本地注释。
发布于 2015-03-22 11:24:53
向表达式中添加类型注释,如
e :: type使编译器检查e是否有该type,并使用该type驱动类型变量实例化和实例选择。但是,如果type是多态的,那么以后仍然可以实例化它。考虑一下。
(id :: a -> a) "hello"上面,a将被实例化为String,尽管我进行了注释。此外,
foo :: Int -> Int
foo = (id :: a -> a)将使a在稍后被实例化为Int。上面的id注释没有向GHC提供任何信息:它已经知道id有这种类型。我们可以在不影响类型检查的情况下删除它。也就是说,表达式id和id :: a->a不仅是动态等效的,而且在静态上也是等价的。
类似地,表达式
putStrLn . show和
(putStrLn . show) :: Show x => x -> IO ()静态等效:我们只是用GHC可以推断的类型对代码进行注释。换句话说,我们没有向GHC提供任何它还不知道的信息。
在对注释进行类型检查之后,GHC可以进一步实例化x。在你的例子中,单态限制就是这样做的。要防止这种情况,请为您要引入的绑定使用注释,而不是对表达式使用注释。
myprint :: Show x => x -> IO ()
myprint = (putStrLn . show)https://stackoverflow.com/questions/29193338
复制相似问题