How to print type of polymorphic function (or value) in ghci with type defaulting rules applied?

Viewed 282

When I enter :t command in GHCi I see polymorphic type:

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

But after I actually evaluate such functions I see result of type defaulting rules. Is there some command or ability to observe in ghci how type will be changed after type defaulting rules applied according to Haskell report and/or ghc implementation?

4 Answers

Since GHC 8.4.1 it's possible to use :type +d (or :t +d for short) option to print the type of an expression, defaulting type variables if possible.

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

It's not really possible for ghci to give you similar defaulting behaviour as GHC, which is exactly why the monomorphism restriction is (now) turned off by default in ghci.

As shown in @Shersh's answer, you can now ask GHCi what it would default a given expression to.

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

But this isn't necessarily reflective of what GHC would do with the same expression, since GHC compiles the expression in the context of the full module. GHC can take into account all uses of the expression, where as GHCi only has access to the constituent parts of the expression. GHC only defaults things that remain ambiguous after considering all of that extra context, so it isn't guaranteed to use the type for the expression that you would see with :t +d in GHCi.

For example:

n = 2^100 `div` 2

xs = "ABCD"

main = print $ xs !! n

This prints 'A', which is obviously not the 633825300114114700748351602688th element of that (4-element) list. Because the expression 2^100 `div` 2 is used as an argument to !! (non-locally, via the n binding), and (!!) :: [a] -> Int -> a the type is chosen as Int, not the type that would be chosen by default without this context (Integer). Evaluating that expression as Int has a different result (0, due to overflow).

This means that when you're scratching your head over a type error in GHC and are using :t +d in GHCi to try to get more information, you need to be aware that you still might not be seeing the same type that GHC is actually using. The polymorphic type is guaranteed to be compatible with the one GHC is using, but defaulting it in any other context might result in a different one that is not compatible.

Related