当我:t
在 GHCi 中输入命令时,我看到多态类型:
ghci> :t 42
42 :: Num t => t
ghci> :t div
div :: Integral a => a -> a -> a
但是在我实际评估这些函数之后,我看到了类型默认规则的结果。是否有一些命令或能力可以在 ghci 中观察在根据 Haskell 报告和/或 ghc 实现应用类型默认规则后如何更改类型?
当我:t
在 GHCi 中输入命令时,我看到多态类型:
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 -XMonomorphismRestriction\nlet 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 仅默认在考虑所有额外上下文后仍然模棱两可的事物,因此不能保证使用您:t +d
在 GHCi 中看到的表达式的类型。
例如:
n = 2^100 `div` 2
xs = "ABCD"
main = print $ xs !! n
这将打印'A'
,这显然不是该(4 元素)列表的第 633825300114114700748351602688 个元素。因为表达式2^100 `div` 2
被用作!!
(非本地,通过n
绑定)的参数,并且(!!) :: [a] -> Int -> a
类型被选择为Int
,而不是在没有此上下文 ( Integer
) 的情况下默认选择的类型。将该表达式评估为Int
具有不同的结果(0,由于溢出)。
这意味着当您为 GHC 中的类型错误而摸不着头脑并:t +d
在 GHCi 中使用以尝试获取更多信息时,您需要注意您可能仍然没有看到 GHC 实际使用的相同类型。保证多态类型与 GHC 正在使用的一个兼容,但在任何其他上下文中默认它可能会导致另一个不兼容的类型。