如何正确地将编译时信息传递给Template Haskell函数?

Pet*_*lák 69 haskell compile-time template-haskell

我需要将编译脚本中的一些信息传递给Template Haskell.目前编译脚本将信息保存在系统环境中,所以我只是使用System.Environment.getEnvironmentwrap in来读取它runIO.有没有更好的方法,例如传递一些参数ghc(类似于-D...C预处理器),或者也许是为TH专门为此目的而设计的东西?

Pet*_*lák 13

既然有这么多人对这个问题感兴趣,我会添加我目前的方法,也许有人会发现它很有用.可能最好的方法是如果TH允许-D在GHC的命令行上读取参数,但似乎没有像现在这样的实现.

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

{-# 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
Run Code Online (Sandbox Code Playgroud)

它可以像这样使用:

{-# LANGUAGE TemplateHaskell #-}
import THEnv
main = print $( lookupCompileEnvExp "DEBUG" )
Run Code Online (Sandbox Code Playgroud)

然后:

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


jak*_*122 3

看起来就像您在这里尝试执行的操作,ghc 中的 -D 选项似乎定义了一个编译时变量。

在这里,关于同一主题的一个问题似乎也回答了您问题的另一部分。据我所知,要进行条件编译,您需要执行以下操作:

    #ifdef MACRO_NAME
    //Do stuff here
    #endif
Run Code Online (Sandbox Code Playgroud)