GHCi 忽略类型签名
GHCi ignores type signature
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 按照我的实际意图去做吗?
我们可以执行以下操作,单态限制为:
>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
绑定,在右侧有一个类型注释。单态性检查顶级类型签名,但不检查本地注释。
向表达式添加类型注释,如
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
。单态限制在您的示例中执行此操作。为防止这种情况,请为您要引入的 binding 使用注释,而不是为 expression:
myprint :: Show x => x -> IO ()
myprint = (putStrLn . show)
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 按照我的实际意图去做吗?
我们可以执行以下操作,单态限制为:
>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
绑定,在右侧有一个类型注释。单态性检查顶级类型签名,但不检查本地注释。
向表达式添加类型注释,如
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
。单态限制在您的示例中执行此操作。为防止这种情况,请为您要引入的 binding 使用注释,而不是为 expression:
myprint :: Show x => x -> IO ()
myprint = (putStrLn . show)