我正在Haskell中的简单编程语言解释器上工作,在定义标准库时,我遇到了一些麻烦。我希望将其定义为Toplevel的静态字符串,并与我的解释器一起编译:
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
来实现这一目标,但是由于其他一些问题,因此不可能有这样的报价。
如何以最方便的方式进行操作?
如注释中所建议的,模板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
的内联。
要使用此功能,必须在单独的模块中定义$()
中调用的任何功能,而不是调用它。