Подтвердить что ты не робот

Как правильно сообщать информацию времени компиляции в функции Template Haskell?

Мне нужно передать некоторую информацию из скриптов компиляции в Template Haskell. В настоящее время скрипты компиляции хранят информацию в системной среде, поэтому я просто прочитал ее, используя System.Environment.getEnvironment, завернутый в runIO. Есть ли лучший способ, например, передать некоторые аргументы ghc (аналогично -D... для предварительного процессора C) или, возможно, что-то специально предназначенное для этой цели в TH?

4b9b3361

Ответ 1

Поскольку так много людей интересует вопрос, я добавлю свой нынешний подход, возможно, кто-то найдет его полезным. Вероятно, лучшим способом было бы, если бы 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 [email protected]
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 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 not
-- present. The result is a TH expression of type @[email protected]
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".

Ответ 2

Похоже на то, что вы пытаетесь сделать здесь. Опция -D в ghc, похоже, определяет переменную времени компиляции.

Здесь по этому вопросу есть question, который, как представляется, также отвечает на другую часть вашего вопроса. Из того, что я могу сказать, чтобы выполнить условную компиляцию, вы делаете что-то вроде:

    #ifdef MACRO_NAME
    //Do stuff here
    #endif