我怎样才能使这个 monad 堆栈可重用?

问题描述

我正在为一种简单的编程语言编写解释器。它有两个阶段:解析器和评估器。解析器读取文本文件并使用表达式、值等创建树。它还进行一些验证。这是我正在使用的 monad 堆栈:

type Type = IntT | BoolT | CharT
data FunEnv = [String]
data VarEnv = [(String,Type)]
type ParserEnv r = StateT (FunEnv,VarEnv) (Except String) r

函数环境存储已定义函数名称,变量环境存储已定义变量的类型。当解析器读取文件并找到函数或变量定义时,它将它们添加到状态中。解析器也可能失败,这就是我使用 Except monad 的原因。

在那之后,是评估者。求值器也需要一个类似的 monad 堆栈,但它不需要存储变量的类型,而是需要存储它们正在存储的值:

type Value = IntV Int | BoolV Bool | CharV Char
data FunEnv = [String]
data VarEnv = [(String,Value)]
type EvaluatorEnv r = StateT (FunEnv,VarEnv) (Except String) r

所以,为了能够复用之前的栈,我想到了重构,使其更通用:

data FunEnv = [String]
type VarEnv a = [(String,a)]
type Env a r = StateT (FunEnv,VarEnv a) (Except String) r

现在 FunEnvVarEnv 更通用,因此我可以使用相同的 monad 堆栈为解析器和求值器定义类型:

type ParserEnv r = Env Type r
type EvaluatorEnv r = Env Value r

尽管这使与 monad 在低级别交互的函数类型有点复杂,但它是有效的。然而,问题是评估器必须能够执行 IO 操作,所以我需要 IO monad 作为我的堆栈的核心。再一次,我可以概括我的堆栈来说明这一点:

type Env a m r = StateT (FunEnv,VarEnv a) (ExceptT String m) r

如您所见,我添加一个参数 m,它是堆栈核心的 monad,我使用的是 ExceptT 而不是 Except。现在,我可以重新定义以 Identity 为核心的解析器 monad,以及以 IO 为核心的评估器 monad:

type ParserEnv r = Env Type Identity r
type EvaluatorEnv r = Env Value IO r

在这方法中看到的一个缺点是,我需要为 mtl monad 使用 Identity 包,但更重要的是,它使低级函数的类型更加复杂。用于获取与变量关联的内容的通用函数的类型如下所示:

getvariable :: Monad m => String -> Env a m (Maybe a)

也许我想得太多了,我的解决方案没问题,但我很感激第二个意见。 有没有更好的方法来使这个 monad 堆栈通用?还是行为差异太大,我应该分别实现两次?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...