¿Cómo comunicar correctamente la información en tiempo de compilación a las funciones de Template Haskell?
compile-time template-haskell (2)
Necesito comunicar algo de información de los scripts de compilación en Template Haskell. Actualmente, los scripts de compilación mantienen la información en el entorno del sistema, por lo que solo la leo usando System.Environment.getEnvironment
envuelto en runIO
. ¿Hay una manera mejor, como pasar algunos argumentos a ghc
(similar a -D...
para el preprocesador C), o tal vez algo específicamente diseñado para este propósito en TH?
Dado que muchas personas están interesadas en la pregunta, agregaré mi enfoque actual, tal vez alguien lo encuentre útil. Probablemente, la mejor forma sería si TH permitiera leer los parámetros -D
en la línea de comando de GHC, pero parece que esto no se implementa en la actualidad.
Un módulo simple permite a TH leer el entorno de tiempo de compilación. Una función auxiliar también permite leer archivos; por ejemplo, lea la ruta de un archivo de configuración desde el entorno y luego lea el archivo.
{-# 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
Se puede usar así:
{-# LANGUAGE TemplateHaskell #-}
import THEnv
main = print $( lookupCompileEnvExp "DEBUG" )
Entonces:
-
runhaskell Main.hs
imprimeNothing
; -
DEBUG="yes" runhaskell Main.hs
printsJust "yes"
.
Parece que lo que está tratando de hacer here , la opción -D en ghc parece definir una variable de tiempo de compilación.
Aquí, sobre el mismo tema, hay una question que parece responder también a la otra parte de su pregunta. Por lo que puedo decir, para hacer una compilación condicional, haces algo como:
#ifdef MACRO_NAME
//Do stuff here
#endif