如何正确地传递编译时信息到模板Haskell函数?

我需要将编译脚本中的一些信息传递给模板Haskell。 目前编译脚本将信息保存在系统环境中,所以我只是使用包裹在runIO System.Environment.getEnvironment读取它。 有没有更好的方法,比如将一些parameter passing给ghc (类似于-D...对于C预处理器),或者可能是在TH中专门为此目的而devise的?

既然有这么多人对这个问题感兴趣,我会加上我目前的方法,也许有人会觉得它有用。 如果TH允许读取GHC命令行中的-D参数,那么最好的办法可能是这样,但是目前看起来并没有这样做。

一个简单的模块允许TH读取编译时环境。 辅助函数也允许读取文件; 例如从环境中读取configuration文件的path,然后读取该文件。

 {-# LANGUAGE TemplateHaskell #-} module THEnv ( -- * Compile-time configuration lookupCompileEnv , lookupCompileEnvExp , getCompileEnv , getCompileEnvExp , fileAsString ) where import Control.Monad import qualified Data.Text as T import qualified Data.Text.IO as T import Language.Haskell.TH import Language.Haskell.TH.Syntax (Lift(..)) import System.Environment (getEnvironment) -- Functions that work with compile-time configuration -- | Looks up a compile-time environment variable. lookupCompileEnv :: String -> Q (Maybe String) lookupCompileEnv key = lookup key `liftM` runIO getEnvironment -- | Looks up a compile-time environment variable. The result is a TH -- expression of type @Maybe String@. lookupCompileEnvExp :: String -> Q Exp lookupCompileEnvExp = (`sigE` [t| Maybe String |]) . lift <=< lookupCompileEnv -- We need to explicly type the result so that things like `print Nothing` -- work. -- | Looks up an compile-time environment variable and fail, if it's not -- present. getCompileEnv :: String -> Q String getCompileEnv key = lookupCompileEnv key >>= maybe (fail $ "Environment variable " ++ key ++ " not defined") return -- | Looks up an compile-time environment variable and fail, if it's not -- present. The result is a TH expression of type @String@. getCompileEnvExp :: String -> Q Exp getCompileEnvExp = lift <=< getCompileEnv -- | Loads the content of a file as a string constant expression. -- The given path is relative to the source directory. fileAsString :: FilePath -> Q Exp fileAsString = do -- addDependentFile path -- works only with template-haskell >= 2.7 stringE . T.unpack . T.strip <=< runIO . T.readFile 

它可以像这样使用:

 {-# LANGUAGE TemplateHaskell #-} import THEnv main = print $( lookupCompileEnvExp "DEBUG" ) 

然后:

  • runhaskell Main.hs打印Nothing ;
  • DEBUG="yes" runhaskell Main.hs打印Just "yes"

它看起来像你在这里试图做的,ghc中的-D选项似乎定义了一个编译时间variables。

在这里,同一个问题似乎也回答了你的问题的其他部分。 从我可以告诉的是,做有条件的编译,你做的事情是这样的:

  #ifdef MACRO_NAME //Do stuff here #endif