Search code examples
haskelltypesfunctional-programmingtype-systemspolymorphic-functions

Can I print in Haskell the type of a polymorphic function as it would become if I passed to it an entity of a concrete type?


Here's a function polymorphic in 3 types:

:t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c

and here a non polymorphic function:

:t Data.Char.digitToInt
Data.Char.digitToInt :: Char -> Int

If we apply the former to the latter, we get a function polymorphic in 1 type:

:t (.) Data.Char.digitToInt
(.) Data.Char.digitToInt :: (a -> Char) -> a -> Int

which means that (.) was "instantiated" (I'm not sure this is the correct term; as a C++ programmer, I'd call it so) with b === Char and c === Int, so the signature of the (.) that gets applied to digitToInt is the following

(Char -> Int) -> (a -> Char) -> a -> Int

My question is: is there a way to have this signature printed on screen, given (.), digitToInt and the "information" that I want to apply the former to the latter?

For who's interested, this question was earlier closed as duplicate of this one.


Solution

  • Other answers require the help of functions that have been defined with artificially restricted types, such as the asTypeOf function in the answer from HTNW. This is not necessary, as the following interaction shows:

    Prelude> let asAppliedTo f x = const f (f x)
    
    Prelude> :t head `asAppliedTo` "x"
    head `asAppliedTo` "x" :: [Char] -> Char
    
    Prelude> :t (.) `asAppliedTo` Data.Char.digitToInt
    (.) `asAppliedTo` Data.Char.digitToInt
      :: (Char -> Int) -> (a -> Char) -> a -> Int
    

    This exploits the lack of polymorphism in the lambda-binding that is implicit in the definition of asAppliedTo. Both occurrences of f in its body must be given the same type, and that is the type of its result. The function const used here also has its natural type a -> b -> a:

    const x y = x