来自C ++,我习惯于能够构建简单形式的编译时断言,如果通过使用模板元素无法满足某些简单条件(例如,通过简单的代数表达式),我可以在编译期间发出警告或错误 - 编程和/或 cpp(1)
例如,如果我想确保我的程序只在何时编译 Int
至少有一定的 minBound
/maxBound
范围或者,如果是无损失(如可逆)转换 Int64
至 Int
可以使用当前编译目标。这可能是GHC Haskell扩展的一部分吗?我的第一个猜测是使用TH。是否有其他GHC设施可以被利用?
来自C ++,我习惯于能够构建简单形式的编译时断言,如果通过使用模板元素无法满足某些简单条件(例如,通过简单的代数表达式),我可以在编译期间发出警告或错误 - 编程和/或 cpp(1)
例如,如果我想确保我的程序只在何时编译 Int
至少有一定的 minBound
/maxBound
范围或者,如果是无损失(如可逆)转换 Int64
至 Int
可以使用当前编译目标。这可能是GHC Haskell扩展的一部分吗?我的第一个猜测是使用TH。是否有其他GHC设施可以被利用?
这是一个广义的,略微简化的版本 安东尼的榜样:
{-# LANGUAGE TemplateHaskell #-}
module StaticAssert (staticAssert) where
import Control.Monad (unless)
import Language.Haskell.TH (report)
staticAssert cond mesg = do
unless cond $ report True $ "Compile time assertion failed: " ++ mesg
return [] -- No need to make a dummy declaration
用法:
{-# LANGUAGE TemplateHaskell #-}
import StaticAssert
$(staticAssert False "Not enough waffles")
使用TH来做到这一点并不算太糟糕。这是一个模块,它定义了所需的断言作为残留声明的一部分:
{-# LANGUAGE TemplateHaskell #-}
module CompileTimeWarning where
import Control.Monad (unless)
import Data.Int (Int64)
import Language.Haskell.TH
assertInt = let test = fromIntegral (maxBound::Int) == (maxBound::Int64)
in do unless test $ report True "Int is not safe!"
n <- newName "assertion"
e <- fmap NormalB [|()|]
return $ [FunD n [Clause [] e []]]
使用断言涉及一个顶级声明,该声明不用于断言以外的任何内容:
{-# LANGUAGE TemplateHaskell #-}
import CompileTimeWarning
$(assertInt)