当我在ghci中输入 :t
命令时,我会看到多态性类型:
ghci> :t 42
42 :: Num t => t
ghci> :t div
div :: Integral a => a -> a -> a
但是在我实际评估了此类功能之后,我会看到类型默认规则的结果。是否有某些命令或能力可以在GHCI中观察到根据Haskell报告和/或GHC实现应用类型默认规则后将如何更改类型?
您可以通过打开单态限制,然后将其绑定到新名称:
来做到这一点:Prelude> :set -XMonomorphismRestriction
Prelude> let n = 42
Prelude> :t n
n :: Integer
Prelude> let p = (^)
Prelude> :t p
p :: Integer -> Integer -> Integer
Prelude> let e = (**)
Prelude> :t e
e :: Double -> Double -> Double
Prelude> let d = div
Prelude> :t d
d :: Integer -> Integer -> Integer
如果您不喜欢始终定义一个新变量,则可以使用
来解决此问题Prelude> :def monotype (e -> return $ ":set -XMonomorphismRestrictionnlet defaulted = "++e++"n:t defaulted")
(您可能需要将其放在.ghci
文件中,以始终具有可用的命令)然后
Prelude> :monotype (^)
defaulted :: Integer -> Integer -> Integer
当然,实现单态限制的隐藏全球副作用非常丑陋,但是哦,好吧...
不是一个完美的解决方案,但这可能是第一步。
> import Data.Typeable
> let withType x = (x, typeOf x)
> withType []
([],[()])
> withType 56
(56,Integer)
请注意,由于a
类型已更改为(a,TypeRep)
,因此GHCI不会使用其所有默认魔法。不过,可以显示其中的一些。
GHCI的:set +t
选项也很有趣,但是在GHCI违约之前打印了多态性类型,似乎。
由于GHC 8.4.1,可以使用:type +d
(或简短的:t +d
)选项打印表达式的类型,如果可能的话,默认类型变量。
ghci> :t 42
42 :: Num p => p
ghci> :t +d 42
42 :: Integer
ghci> :t div
div :: Integral a => a -> a -> a
ghci> :t +d div
div :: Integer -> Integer -> Integer
GHCI真的不可能给您与GHC相似的默认行为,这正是为什么单态限制(现在)在GHCI中被默认关闭的原因。
。如 @Shersh的答案所示,您现在可以询问GHCI默认给定表达式的内容。
Prelude> :t 2^100 `div` 2
2^100 `div` 2 :: Integral a => a
Prelude> :t +d 2^100 `div` 2
2^100 `div` 2 :: Integer
Prelude> 2^100 `div` 2
633825300114114700748351602688
,但这不一定反映GHC对相同表达式的作用,因为GHC在完整模块的上下文中编译了表达式。GHC可以考虑表达式的所有使用,因为GHCI只能访问表达式的组成部分。GHC仅在考虑所有额外上下文之后默认含糊不清的事物,因此不能保证使用GHCI中:t +d
看到的表达式的类型。
例如:
n = 2^100 `div` 2
xs = "ABCD"
main = print $ xs !! n
这是打印'A'
,显然不是该(4个元素)列表的6333825300114114114114114114114748351688TH。因为表达式 2^100 `div` 2
是使用的作为 !!
的参数(非局部,通过 n
绑定),而 (!!) :: [a] -> Int -> a
类型是Int
,而不是默认情况下选择的类型,而没有此上下文。(Integer
)。评估该表达为Int
的结果不同(0,由于溢出)。
这意味着,当您在GHC中的类型错误上划痕并在GHCI中使用:t +d
来尝试获取更多信息时,您需要意识到您仍然可能没有看到与GHC相同的类型实际使用。保证多态类型与GHC使用的一个类型兼容,但是在任何其他上下文中默认情况下可能会导致不同的一种。