【Hacker News搬运】推论和效果
-
Title: Coroutines and effects
推论和效果
Text:
Url: https://without.boats/blog/coroutines-and-effects/
文章标题为“Coroutines and effects”,作者探讨了效应系统(effect systems)与协同程序(coroutines)之间的关系。效应系统类似于Koka语言中的那种,而协同程序则类似于Rust的异步函数或生成器。作者分析了两者之间的差异,试图找出各自的优缺点。 协同程序是一种可以在完成前将控制权返回给调用者的函数。调用者可以引用协同程序在让出控制时的状态,以便在选择时恢复协同程序。通过使协同程序让出,可以模拟许多有意义的“效应”。例如,协同程序可以异步执行IO,通过在执行IO时让出一个值(如`Pending`)来实现;协同程序可以通过在遍历某些集合时让出值来使其可迭代;协同程序可以通过让出一个异常值来模拟异常。 效应处理器则是一种处理具有效应的表达式,产生一个不具有该效应的表达式的机制。并非所有效应都可以处理(例如,据作者理解,无法有意义地处理发散效应),但有些可以。处理效应的语义是效应系统与协同程序相似之处。 协同程序与效应处理器之间的关键区别在于,协同程序将控制权让给它们的调用者,而具有效应的表达式将控制权让给它们的处理器。这暗示了协同程序相对于效应处理器在功能上的显著优势。 文章最后,作者得出结论,协同程序是处理许多种效应函数最有前途的方法,因为它们似乎处于设计上的甜蜜点:它们是静态类型、词法作用域和无层级的。因此,在任何语言中处理效应的起点应该是协同程序特征。
Post by: todsacerdoti
Comments:
et1337: Wow I’ve been thinking of something exactly like this! Sort of a super charged, statically typed version of Go’s context.Context. It would allow you to describe the capabilities (or effects) of every function, including IO, memory allocation, cancellation, deadlines, concurrency, and whatever application-specific stuff you need on there (like logging).<p>Then you could implement something like Google capslock [0] just by looking at type signatures.<p>0. <a href="https://github.com/google/capslock">https://github.com/google/capslock</a>
et1337: 哇,我一直在想这样的事情!有点像Go上下文的超级充电、静态类型版本。上下文它允许您描述每个功能的功能(或效果),包括IO、内存分配、取消、截止日期、并发性,以及您需要的任何特定于应用程序的东西(如日志记录)<p> 然后,您可以通过查看类型签名来实现类似Google capslock[0]的东西<p> 0<a href=“https://;/;github.com/:谷歌/!caplock”>https:///;github.com/;谷歌/;绞盘锁</a>
jeffparsons: > The key difference between coroutines and effect handlers is that coroutines yield control to their caller, but effectful expressions yield control to their handler. The difference of affordance this implies is the materially significant advantage of coroutines over effect handlers.<p>Should that last bit be: "advantage of effect handlers over coroutines"?<p>EDIT: Oh, maybe I should have read the rest of the article first. It might be going the other way than that one example suggested.
jeffparsons: >;协程和效果处理程序之间的关键区别在于,协程将控制权交给调用方,而有效表达式将控制权移交给处理程序。这意味着可供性的差异是协同程序相对于效果处理程序的显著优势<p> 最后一位应该是:“;效果处理程序相对于协同程序的优势”<p> 编辑:哦,也许我应该先读这篇文章的其余部分。它可能会朝着与一个例子所建议的相反的方向发展。:)
amluto: This touches on something I’d like to see in more mainstream languages, but it doesn’t quite get there.<p>> For example, Koka has a “diverging” effect, which means that an expression may diverge (that is to say, it may not finish evaluating). An expression containing a diverging expression is also diverging. So you can distinguish in the type system between a function that is guaranteed to finish and a function that may not finish (this is imperfect, of course, because of the undecidability of the halting problem; some functions that do not diverge will be marked diverging).<p>As I think about it (and I’m not a programming language theorist, nor have I done much serious work in any language with any sort of effect system), there are two vague categories of effect: control-flow effects like exceptions, yields, async waits (Pending, sleep, or however you feel like modeling it) and non-control-flow effects (divergence, various forms of unsafety, nondeterminism, impurity, reads or writes of global state, syscalls in models that don’t treat IO in and of itself as an effect), etc.<p>I would like to be able to run and write code that is <i>definitely</i> free of certain kinds of effects. Xz should not be unsafe or do IO, for example. Leftpad is an entirely pure, non-diverging function. And I should be able to ask my language to enforce that, ideally with trivial code. Maybe even by default.<p>But mainstream languages seem to mostly limit their use of effect-like systems on the control flow part, like this:<p>> Overall, coroutines strike me as the most promising way to handle many kinds of effectful functions because they seem to be in the design sweet spot: They are statically typed, lexically scoped, and unlayered.
amluto: 这触及了我希望在更主流的语言中看到的东西,但它并没有完全实现<p> >;例如,Koka具有“发散”效应,这意味着一个表达式可能会发散(也就是说,它可能不会完成求值)。包含发散表达式的表达式也是发散表达式。因此,你可以在类型系统中区分保证完成的函数和可能不完成的函数(当然,这是不完美的,因为停顿问题的不可判定性;一些不发散的函数将被标记为发散)<p> 正如我所想的(我不是一个编程语言理论家,也没有在任何具有任何类型效果系统的语言中做过太多认真的工作),有两类模糊的效果:控制流效果,如异常、收益、异步等待(挂起、睡眠,或您想对其进行建模的方式)和非控制流效果(分歧、各种形式的不安全、不确定性、杂质、全局状态的读写、不将IO本身视为效果的模型中的系统调用)等。<p>我希望能够运行和编写完全不受某些类型影响的代码。例如,Xz不应该是不安全的或执行IO。Leftpad是一个完全纯的、非发散的函数。我应该能够要求我的语言强制执行这一点,最好是使用琐碎的代码。甚至可能是默认情况下<p> 但主流语言似乎大多限制了它们在控制流部分使用类似效果的系统,如下所示:<p>>;总的来说,协程在我看来是处理多种有效函数的最有前途的方法,因为它们似乎处于设计的最佳位置:它们是静态类型的、词汇范围的和未分层的。
nsm: I am not an expert on this either, although very interested. Note that delimited continuations, which are a superset of coroutines are identical to effects in the sense of yielding control to the handler, not the caller. In languages like Racket/Scheme which allows associating tags with handlers, you can also model the same function having multiple effects.<p>In general, coroutines seem vastly easier to understand/type compared to effects unless your language can do a lot of effect inference.
nsm: 我也不是这方面的专家,尽管我很感兴趣。请注意,定界的延续是协同程序的超集,在将控制权交给处理程序而不是调用程序的意义上,它与效果是相同的。在像Racket/;允许将标记与处理程序关联的方案,您还可以对具有多种效果的同一函数进行建模<p> 一般来说,协同作业似乎更容易理解;类型与效果相比,除非你的语言能做很多效果推理。
kodablah: > Overall, coroutines strike me as the most promising way to handle many kinds of effectful functions<p>This is basically what we do at Temporal, which is essentially deterministic coroutines with externalized effects. This gives another nice property: using coroutines to wrap effects lets the non-effect logic replay/resume durably.
kodablah: >;总的来说,协程在我看来是处理多种有效函数的最有前途的方法<p>这基本上就是我们在Temporal中所做的,它本质上是具有外部效果的确定性协程。这提供了另一个很好的特性:使用协程来包装效果可以让非效果逻辑重放;持久地恢复。