2012-05-01 11 views
11

Estoy buscando una función que haga lo que hace el comando GHCi: type.Haskell: obteniendo el tipo estático de una expresión

Lo ideal sería tener una firma algo así como

getStaticType :: a -> String 

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

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

(Nota: De hecho la función wouldn' esto no tiene nada que ver con Data.Dynamic Sólo quiero que el tipo estático inferirse del compilador.. t necesidad de una aplicación en tiempo de ejecución en absoluto, ya que todas las llamadas a que podría ser entre líneas como constantes en tiempo de compilación estoy asumiendo que existe en algún lugar, ya que GHCi puede hacerlo)

Respuesta

20

puede hacerlo de esta manera:.

import Data.Typeable 

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

Tenga en cuenta que el tipo debe ser una instancia de Typeable. Puede derivar Typeable automáticamente utilizando la extensión de idioma Haskell DeriveDataTypeable y ... deriving (Typeable, ...).

También tenga en cuenta que los tipos polimórficos no se pueden identificar de esta manera; siempre debe llamar a una función con un tipo específico , de modo que nunca pueda obtener esa información de tipo polimórfico que obtiene en GHCi con el código compilado Haskell.

La forma en que GHCi lo hace es que utiliza la API de GHC para analizar un árbol de sintaxis abstracta (AST) de Haskell intermediario que contiene información de tipo. GHCi no tiene el mismo entorno restringido que su programa compilado típico de Haskell; puede hacer muchas cosas para obtener más información sobre su entorno.

Con TemplateHaskell, puede hacerlo así; En primer lugar, crear este módulo:

module TypeOf where 

import Control.Monad 

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

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

Luego, en un módulo diferente (muy importante), puede hacer lo siguiente:

salidas
{-# LANGUAGE TemplateHaskell #-} 

import TypeOf 

main = putStrLn $(getStaticType 'zipWith) 

Este programa:

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

Puede usar una mejor impresora que la función pprint; Eche un vistazo al módulo Language.Haskell.TH.Ppr.

+0

el uso es para el código de auto-documentación y registro. Es una lástima que no sea posible, parece que sería trivial implementarlo como una "función mágica" en el compilador, que ya tiene toda la información. – drwowe

+5

TBH, Haskell es bastante fuerte "anti-magia". –

+0

@drwowe es correcto, sería bastante fácil de implementar en un compilador. Sería una especie de función de tiempo de compilación como * sizeof * en C. – Ingo

1

tratar http://www.haskell.org/haskellwiki/GHC/As_a_library

typed targetFile targetModule = do 
defaultErrorHandler defaultFatalMessager defaultFlushOut $ do 
    runGhc (Just libdir) $ do 

    dflags <- getSessionDynFlags 
    let dflags' = xopt_set dflags Opt_ImplicitPrelude 
    setSessionDynFlags dflags' 

    target <- guessTarget targetFile Nothing 
    setTargets [target] 
    load LoadAllTargets 

    m <- getModSummary $ mkModuleName targetModule 
    p <- parseModule m 
    t <- typecheckModule p 

    return $ typecheckedSource d 
Cuestiones relacionadas