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

时间:2019-03-20 14:50:30

标签: haskell metaprogramming template-haskell

我正在用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返回Left时我的解释器根本不编译,如以下示例所示:

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

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

我试图在为我的语言定义QuasiQuotation时使用fail来实现此目的,但是由于其他一些问题,无法使用这样的报价。

如何以最方便的方式做到这一点?

1 个答案:

答案 0 :(得分:1)

如评论中所建议,模板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

要使用此功能,在$()中调用的任何函数都必须在与调用位置不同的单独模块中定义。