Serialization 在函数式解释器中序列化正在运行的程序

Serialization 在函数式解释器中序列化正在运行的程序,serialization,functional-programming,interpreter,monads,continuations,Serialization,Functional Programming,Interpreter,Monads,Continuations,我正在编写一个解释器,该解释器使用Cont Monad的变体在功能上实现。受Smalltalk使用图像捕获正在运行的程序的启发,我正在研究如何序列化正在执行的托管程序,并需要帮助确定如何在高级别上完成此任务 问题陈述 使用contmonad,我可以在解释器中捕获正在运行的程序的当前延续。存储当前延续允许通过调用延续来恢复解释器执行。我想序列化此延续,以便运行程序的状态可以保存到磁盘或由另一个解释器实例加载。但是,我的语言(我的目标和工作都是Javascript)不支持以这种方式序列化函数 我对一

我正在编写一个解释器,该解释器使用Cont Monad的变体在功能上实现。受Smalltalk使用图像捕获正在运行的程序的启发,我正在研究如何序列化正在执行的托管程序,并需要帮助确定如何在高级别上完成此任务

问题陈述 使用contmonad,我可以在解释器中捕获正在运行的程序的当前延续。存储当前延续允许通过调用延续来恢复解释器执行。我想序列化此延续,以便运行程序的状态可以保存到磁盘或由另一个解释器实例加载。但是,我的语言(我的目标和工作都是Javascript)不支持以这种方式序列化函数

我对一种方法感兴趣,这种方法可以用于在给定的执行点(给定一些元数据)构建延续,而无需再次运行整个程序,直到它达到该点为止。最好对解释器本身的实现进行最小的更改

深思熟虑的方法 一种可能有效的方法是将所有控制流逻辑推入程序状态。例如,我目前使用宿主语言对循环行为的递归来表示一个C风格的For循环:

var forLoop = function(init, test, update, body) {
    var iter = function() {
        // When test is true, evaluate the loop body and start iter again
        // otherwise, evaluate an empty statement and finish
        return branch(test,    
            next(             
                next(body, update),
                iter()),
             empty);
    };

    return next(
        init,
        iter());
};
这是一个很好的解决方案,但是如果我在for循环中途暂停程序,我不知道如何序列化已经建立的延续

我知道我可以使用跳转序列化转换后的程序,但是for循环可以通过跳转操作构造。我的解释器的第一步将生成代码块并将它们保存在程序状态。这些块将捕获托管语言中的某些操作,并可能执行其他块。预处理程序的外观如下所示:

Label         Actions (Block of code, there is no sequencing)
-----------------------------------
start:        init, GOTO loop

loop:         IF test GOTO loop_body ELSE GOTO end

loop_body:    body, GOTO update

update:       update, GOTO loop

end:          ...
这使得每个代码块独立,仅依赖于存储在程序状态中的值

为了序列化,我将保存当前标签名和输入时的状态。反序列化将预处理输入代码以再次构建标签,然后以给定状态在给定标签处恢复。但现在,在实现解释器时,我必须考虑这些块。甚至用构图来隐藏其中的一些内容似乎也有点难看

问题:
有没有解决这个问题的好方法?我是不是想用完全错误的方式序列化一个程序?对于这样的结构,这是可能的吗?

经过更多的研究,我对如何做到这一点有了一些想法。但是,我不确定添加序列化是否是我现在想做的事情,因为它会对实现的其余部分产生很大影响

我对这种方法不满意,并且非常希望听到任何替代方案

问题 正如我所指出的,将程序转换为语句列表使序列化更容易。整个程序可以转换成汇编语言,但我想避免这种情况

保持表达式的概念,我原先没有考虑的是函数调用可以发生在深嵌套表达式中。以这个项目为例:

function id(x) { return x; }
10 + id(id(5)) * id(3);
序列化程序应该能够在任何语句中序列化程序,但该语句可能会在表达式中进行计算

主机功能处于该状态

程序状态无法轻松序列化的原因是它包含用于继续的主机函数。这些延续必须转换为数据结构,这些数据结构可以序列化并独立地重构为原始延续所表示的动作。去功能化最常用于以一阶语言表示高阶语言,但我相信它也可以实现序列化

不是所有的连续体都可以在不大幅重写解释器的情况下轻易地失效。由于我们只对特定点上的序列化感兴趣,因此在这些点上的序列化需要解除整个延续堆栈的功能。所以所有语句和表达式都必须失效,但内部逻辑在大多数情况下可以保持不变,因为我们不希望通过内部操作部分地允许序列化

然而,据我所知,由于bind语句,取消功能化在Cont Monad中不起作用。由于缺乏良好的抽象,因此很难使用

关于解决办法的思考 目标是创建一个仅由简单数据结构组成的对象,该对象可用于重建整个程序状态

首先,为了最小化所需的工作量,我将重写语句级解释器,以使用更像状态机的东西,从而更容易序列化。然后,我会解除表达式的功能。函数调用会将剩余表达式的失效延续推送到状态机的内部堆栈上

使程序状态成为可序列化对象

看看语句是如何工作的,我不相信Cont Monad是将语句链接在一起的最佳方法(但我确实认为它在表达式级别和内部操作方面工作得非常好)。状态机似乎是更自然的方法,这也更容易序列化

将编写一台在语句之间进行步进的机器。该状态中的所有其他结构也将可序列化。内置函数必须使用可序列化句柄来标识它们,以便没有函数处于该状态

处理表达式

表达式将被重写以传递失效的延续,而不是宿主函数延续。当在表达式中遇到函数调用时,它捕获失效的当前继续并将其推送到