我正在用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
。而且,它不会给我任何有关解析和类型检查错误的反馈。我希望如果parse
或typecheck
返回Left
时我的解释器根本不编译,如以下示例所示:
stdLibString = "≠²³¢©œęæśð"
-- Compilation error: "cannot parse definition"
stdLib = either (error . show) id $ parse stdLibStr >>= typecheck
我试图在为我的语言定义QuasiQuotation时使用fail
来实现此目的,但是由于其他一些问题,无法使用这样的报价。
如何以最方便的方式做到这一点?
答案 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
。
要使用此功能,在$()
中调用的任何函数都必须在与调用位置不同的单独模块中定义。