我正在寻找一个能完成GHCi:type命令的功能。
理想情况下,它会有像
这样的签名getStaticType :: a -> String
a = getStaticType (1+2)
-- a = "(Num t) => t"
b = getStaticType zipWith
-- b = "(a -> b -> c) -> [a] -> [b] -> [c]"
(注意:这与Data.Dynamic无关。我只想从编译器推断出静态类型。事实上,该函数根本不需要运行时实现,因为对它的所有调用都可以内联为编译时的常量。我假设它存在于某个地方,因为GHCi可以做到这一点)
答案 0 :(得分:20)
你可以这样做:
import Data.Typeable
getStaticType :: Typeable a => a -> String
getStaticType = show . typeOf
请注意,该类型必须是Typeable
的实例。您可以使用Typeable
Haskell语言扩展程序和DeriveDataTypeable
自动派生... deriving (Typeable, ...)
。
另请注意,无法以这种方式识别多态类型;您必须始终使用特定的类型调用函数,因此您永远无法获得使用已编译的Haskell代码在GHCi中获得的多态类型信息。
GHCi的工作方式是它使用GHC API来分析包含类型信息的中间Haskell抽象语法树(AST)。 GHCi没有与典型编译的Haskell程序相同的受限环境;它可以做很多事情来找到有关其环境的更多信息。
使用TemplateHaskell,你可以这样做;首先,创建这个模块:
module TypeOf where
import Control.Monad
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
getStaticType :: Name -> Q Exp
getStaticType = lift <=< fmap pprint . reify
然后,在不同模块(非常重要)中,您可以执行以下操作:
{-# LANGUAGE TemplateHaskell #-}
import TypeOf
main = putStrLn $(getStaticType 'zipWith)
该程序输出:
GHC.List.zipWith :: forall a_0 b_1 c_2 . (a_0 -> b_1 -> c_2) ->
[a_0] -> [b_1] -> [c_2]
您可以使用比pprint
功能更好的漂亮打印机;看看Language.Haskell.TH.Ppr
模块。
答案 1 :(得分:1)
尝试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