如何在应用了类型默认规则的ghci中打印多态函数(或值)的类型?

时间:2017-09-13 09:37:38

标签: haskell types polymorphism ghci monomorphism-restriction

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

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

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

4 个答案:

答案 0 :(得分: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

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

答案 1 :(得分:4)

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

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

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

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

答案 2 :(得分: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

答案 3 :(得分: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只会默认仍然含糊的内容,因此不能保证将类型用于您在GHCi中用:t +d看到的表达式。

例如:

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)。将表达式评估为:t +d会有不同的结果(由于溢出,为0)。

这意味着当您为GHC中的类型错误抓狂,并在GHCi中使用for($i=0;$i<5;$i++){ $arr1['a'] = $i; $arr1['b'] = $i+=2; $arr2[] = $arr; //assign the arr1 into the arr2 $arr1= []; //clear arr1 again for the next looping } var_dump($arr2); 尝试获取更多信息时,您需要注意,可能仍然看不到相同的内容GHC实际使用的类型。保证多态类型与所使用的一种GHC兼容,但是在任何其他上下文中将其默认设置可能会导致另一种不兼容。