在编译期间评估表达式并将运行时错误视为编译错误

Eval expression during compilation and treat runtime errors as compilation errors

我正在 Haskell 中开发一个简单的编程语言解释器,但在定义标准库时遇到了一些麻烦。我希望它在顶层被定义为静态字符串并与我的解释器一起编译:

stdLibStr :: String
stdLibStr = "id a := a;;"

parse :: String -> Either Error UntypedModule
typecheck :: UntypedModule -> Either Error TypedModule

-- constexpr
stdLib :: TypedModule
stdLib = either (error . show) id $ parse stdLibStr >>= typecheck

但是,上面的模型不会在编译期间计算 stdLib。此外,它不会给我任何关于解析错误和类型检查错误的反馈。我希望我的解释器在 parsetypecheck returns Left 中不编译,如下例所示:

stdLibString = "≠²³¢©œęæśð"

-- Compilation error: "cannot parse definition"
stdLib = either (error . show) id $ parse stdLibStr >>= typecheck

我在为我的语言定义 QuasiQuotation 时试图使用 fail 来实现这一点,但是由于其他一些问题,不可能有这样的引用。

怎样做最方便?

正如评论中所建议的,模板 Haskell 是执行此操作的方法。下面的函数处理这两种情况:

compileTime :: Lift a => Either String a -> Q Exp
compileTime (Right a) = lift a
compileTime (Left err) = fail err

可以调用为$(compileTime (typecheck =<< parse stdLibStr))。或者它足够短,可以内联为 either fail lift

要使用它,在 $() 中调用的任何函数都必须在与调用它的地方不同的模块中定义。