Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: getting the static type of an expression

Tags:

types

haskell

ghc

I'm looking for a function that does what the GHCi :type command does.

Ideally, it would have a signature something like

getStaticType :: a -> String

a = getStaticType (1+2)
-- a = "(Num t) => t"

b = getStaticType zipWith
-- b = "(a -> b -> c) -> [a] -> [b] -> [c]"

(Note: this has nothing to do with Data.Dynamic. I just want the static type inferred from the compiler. In fact the function wouldn't need a runtime implementation at all, as all calls to it could be inlined as constants at compile time. I'm assuming it exists somewhere, since GHCi can do it)

like image 342
drwowe Avatar asked May 01 '12 15:05

drwowe


1 Answers

You can do it like this:

import Data.Typeable

getStaticType :: Typeable a => a -> String
getStaticType = show . typeOf

Note that the type must be an instance of Typeable. You can derive Typeable automatically using the DeriveDataTypeable Haskell language extension and ... deriving (Typeable, ...).

Also note that polymorphic types cannot be identified in this way; you must always call a function with a specific type, so you can never get that polymorphic type information that you get in GHCi with compiled Haskell code.

The way GHCi does it is that it uses the GHC API to analyse an intermediary Haskell abstract syntax tree (AST) that contains type information. GHCi does not have the same restricted environment that your typical compiled Haskell program does; it can do lots of stuff to find out more information about its environment.

With TemplateHaskell, you can do it like this; first, create this module:

module TypeOf where

import Control.Monad

import Language.Haskell.TH
import Language.Haskell.TH.Syntax

getStaticType :: Name -> Q Exp
getStaticType = lift <=< fmap pprint . reify

Then, in a different module (very important), you can do the following:

{-# LANGUAGE TemplateHaskell #-}

import TypeOf

main = putStrLn $(getStaticType 'zipWith)

This program outputs:

GHC.List.zipWith :: forall a_0 b_1 c_2 . (a_0 -> b_1 -> c_2) ->
                                         [a_0] -> [b_1] -> [c_2]

You can use a better pretty-printer than the pprint function; take a look at the Language.Haskell.TH.Ppr module.

like image 187
dflemstr Avatar answered Oct 30 '22 11:10

dflemstr