在非常简单的意义上,我有以下内容:
type Runtime a = {- More or less a StateT on top of an Either monad -}
-- The list of strings in Fn is a bunch of parameter names, the values of
-- which are pushed into the state of the runtime before executing the actual
-- function expr
data Expr = Num Int
| Str T.Text
| Fn [T.Text] (Runtime Expr)
| {- Bunch of other constructors -}
eval :: Expr -> Runtime Expr
parseExp :: Parser Expr
现在,在我决定为我的玩具语言使用准引用器会很方便之前,我从未将 Template Haskell 用于任何事情,所以我承认我可能会遗漏一些明显的东西。
但无论如何,我开始摆弄它,遵循一些教程等,基本上发现除了如何处理Fn
构造函数之外的一切都很容易。
在网上搜索信息的过程中,我发现了人们写引号的两种一般方式:
- 使他们的
Expr
数据类型成为 TH:s 的实例,Lift
然后简单地 [| 引用 |] 解析产生的表达式 - 导出
Data
和Typeable
等价于Expr
,然后应用于dataToExpQ
相同的解析器结果
在这两种情况下,我都遇到了Runtime Expr
. 对于第一种情况,问题是我不知道如何实现:
instance Lift Expr where
lift (Fn ps e) = [| Fn ps ...? |]
(我确实设法自己实现了 Data.Text 的实例)。
我想真正的问题是我对 TH 的了解还不够好,但是到目前为止,没有多少教程或示例可以帮助我解决这个问题。
在第二种情况下,问题是Expr
要成为 的实例Data
,还需要有一个
instance Data (StateT (...) (Either ...) Expr) where
-- Something
那么我的问题是,是否有一种简单的方法可以做到这一点?或者我应该重新思考我的玩具语言的功能是如何工作的?
如果是后者,关于如何在不在 monad 中运行它们的情况下获得等效功能的任何建议?毕竟,这似乎是一种直观的解决方案,因为该语言的运行时环境需要状态和错误处理(这是我使用Either
的)。