没有显式突变的方案中向后延续的最简单示例
我用 C# 编写了一个小型方案解释器,并意识到我实现它的方式很容易添加对正确延续的支持。
所以我添加了它们......但想“证明”我添加它们的方式是正确的。
然而,我的计划解释器不支持“变异”状态 - 一切都是不可变的。
因此,编写一个单元测试来公开“向上”延续非常容易:
AssertEqual(Eval("(call/cc (lambda (k) (+ 56 (k 3))))"), 3);
但是,我也想编写一个单元测试来证明如果延续“逃逸”,那么它仍然有效:
AssertEqual(Eval("(call/cc (lambda (k) k))", <some continuation>);
但是当然,上面的内容只是测试“我有一个延续”...并不是说它实际上是一个有效的延续。
然而,我能找到的所有示例最终总是使用“set!” 证明转义的延续。
什么是最简单的方案示例,它演示了在不依赖突变的情况下对向后延续的适当支持?
向后延续在没有变异的情况下有什么用吗? 我开始怀疑它们不是,因为你只能用它来再次执行完全相同的计算......如果没有副作用,这是没有意义的。 这就是 Haskell 没有延续的原因吗?
I've written a small Scheme interpreter in C#, and realised that the way I had implemented it, it was very easy to add support for proper continuations.
So I added them... but want to "prove" that they way that I've added them is correct.
My Scheme interpreter however has no support for "mutating" state - everything is immutable.
So it was pretty easy to write a unit test to expose "upwards" continuations:
AssertEqual(Eval("(call/cc (lambda (k) (+ 56 (k 3))))"), 3);
However, I also want to write a unit test that demonstrates that if the continuation "escapes" then that still works too:
AssertEqual(Eval("(call/cc (lambda (k) k))", <some continuation>);
But of course, the above would just test that "I got a continuation"... not that it's actually a valid continuation.
All of the examples I can find, however, always end up using "set!" to demonstrate the escaped continuation.
What's the simplest Scheme example that demonstrates proper support for backwards continuations without relying on mutation?
Are backwards continuations any use without mutation? I am beginning to suspect that they are not, because you could only use it to execute the exact same calculation again... which is meaningless if there are no side-effects. Is this why Haskell does not have continuations?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我不知道这是否是最简单的,但这里有一个使用向后延续的示例,无需调用
set!
或类似的:这应该计算为
8
。稍微有趣的是:
它计算
6!
(也就是说,它的计算结果应该是720
)。你甚至可以用
let*
做同样的事情:(伙计,stackoverflow 的语法高亮在方案上严重失败。)
I don't know if this is the simplest, but here's an example of using backwards continuations without any call to
set!
or similar:This should evaluate to
8
.Slightly more interesting is:
which computes
6!
(that is, it should evaluate to720
).You can even do the same thing with
let*
:(Man, stackoverflow's syntax highlighting fails massively on scheme.)
我认为你是对的——如果没有突变,向后延续就不会做向前延续做不到的事情。
I think you're right -- without mutation, backwards continuations do nothing that forward continuations can't.
这是我想出的最好的:
并不令人惊讶,但它是一个向后的延续,然后我用我希望调用的实际函数“调用”它,一个返回数字 5 的函数。
啊,我也想到了以此作为一个很好的单元测试用例:
我同意 Jacob B - 我认为如果没有可变状态它就没那么有用......但仍然对反例感兴趣。
Here's the best I've come up with:
Not amazing, but it is a backwards continuation which I then "call" with the actual function I wish to invoke, a function that returns the number 5.
Ah and I've also come up with this as a good unit test case:
I agree with Jacob B - I don't think it's that useful without mutable state... but would be still be interested in a counter-example.
函数线程:
您可以使用递归循环来更新状态而不发生突变。 包括下一个要调用的延续的状态。 现在,这比给出的其他示例更复杂,但您真正需要的是
thread-1
和main
循环。 另一个线程和“更新”函数表明延续可以用于不仅仅是一个简单的示例。 此外,为了使该示例正常工作,您需要一个带有命名 let 的实现。 这可以转换为使用定义语句制成的等效形式。示例:
哪个输出
Functional Threads:
You can use a recursive loop to update state without mutation. including the state of the next continuation to be called. Now this is more complicated than the other examples given, but all you really need is the
thread-1
andmain
loop. The other thread and "update" function are there to show that continuations can be used for more than a trivial example. Additionally, for this example to work you need an implementation with the named let. This can be translated into an equivalent form made with define statements.Example:
Which outputs