7

当我:t在 GHCi 中输入命令时,我看到多态类型:

ghci> :t 42
42 :: Num t => t
ghci> :t div
div :: Integral a => a -> a -> a

但是在我实际评估这些函数之后,我看到了类型默认规则的结果。是否有一些命令或能力可以在 ghci 中观察在根据 Haskell 报告和/或 ghc 实现应用类型默认规则后如何更改类型?

4

4 回答 4

5

您可以通过打开单态限制然后将其绑定到一个新名称来做到这一点:

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

当然,启用单态限制的隐藏全局副作用非常难看,但是哦,好吧......

于 2017-09-13T10:49:05.857 回答
4

这不是一个完美的解决方案,但它可能是第一步。

> import Data.Typeable
> let withType x = (x, typeOf x)
> withType []
([],[()])
> withType 56
(56,Integer)

请注意,由于类型已a更改为(a,TypeRep),因此 GHCi 不会使用其所有默认魔法。不过,其中一些可以显示。

GHCi 的:set +t选项也很有趣,但似乎在 GHCi 默认之前打印多态类型。

于 2017-09-13T10:50:34.837 回答
2

从 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
于 2018-08-17T02:42:27.043 回答
1

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 正在使用的一个兼容,但在任何其他上下文中默认它可能会导致另一个不兼容的类型。

于 2018-08-17T03:20:40.653 回答