How can I set up Haskell's GHCI to interactively evaluate functions to their signature (type) instead of getting errors?

246 views Asked by At

To see the function's signature in Haskell GHCI, I have to prefix it with :t:

Prelude> f = \x -> x+1
Prelude> :t f
f :: Num a => a -> a

But typing that prefix every time grows quickly old. If I leave it out, I get error:

Prelude> f

<interactive>:5:1: error:
• No instance for (Show (a0 -> a0)) arising from a use of ‘print’
    (maybe you haven't applied a function to enough arguments?)
• In the first argument of ‘print’, namely ‘it’
  In a stmt of an interactive GHCi command: print it

Instead of getting this error message, I would like see some useful information about my function f similar to the one I get with :t f (possibly even more information about f).

How can I set up the GHCI to achieve this functionality, i.e. getting function's info upon entering it without :t?

2

There are 2 answers

4
dfeuer On

You probably can't do this today. I've opened a feature request to see about adding options to control what GHCi reports about type errors at the prompt.

0
user2407038 On

GHCi will already happily show you the types of anything you type into the prompt, with the option :set +t. The only issue is that show is called on the thing, and there is no proper manner for showing functions - and the type is only printed for an expression which can be shown in a valid manner. However, you can get around this quite easily:

>newtype ShowType a = ShowType a
newtype ShowType a = ShowType a
>instance Show (ShowType a) where show _ = "The type is"
>:set +t
>ShowType const
The type is
it :: ShowType (a -> b -> a)

Unfortunately, this creates quite a lot of syntactic noise. My preferred solution is to add the following to the .ghci file:

:set +t 
instance {-# OVERLAPS #-} Show a where show _ = "The type is"

Adding such a Show instance to any real Haskell module would be a grave mistake, but within the .ghci module, it only scopes over expressions typed into the prompt, so it seems okay to me. With this, you get:

>const
The type is
it :: a -> b -> a
>show
The type is
it :: Show a => a -> String

Conveniently, when you have a function whose type is 'technically' valid but has unsatisfiable constraints, you still get a type error:

>:t \x -> x `div` (x / x)
\x -> x `div` (x / x) :: (Integral a, Fractional a) => a -> a
                         ^^^^^^^^^^^^^^^^^^^^^^^^^^

>\x -> x `div` (x / x)

<interactive>:12:1: error:
    * Ambiguous type variable `a0' arising from a use of `it'
      prevents the constraint `(Fractional a0)' from being solved.

However, the absolute simplest solution is to :set +t and to give a let statement when your expression is non-Showable:

>let _f = show
_f :: Show a => a -> String

Unfortunately, if the left-hand side is the wildcard - let _ = show - then the type is not printed.