原文
原始链接: https://news.ycombinator.com/item?id=40480056
编程中的代数效应允许开发人员以函数方式处理副作用。 我们使用处理程序来管理副作用,而不是在遇到错误时抛出异常。 这是使用异常示例的简单解释: 当函数“Foo”遇到特定的命名函数“Bar”时,它会在其范围内向上搜索处理程序“Baz”。 一旦找到,“Baz”版本的“Bar”就会使用原始参数和“Foo”的其余部分执行。 重复此过程直到“Foo”完成。 在我们的示例中,异常实现会忽略“resume”并仅包含一个函数“throw”。 我们定义一个“printExceptions”处理程序来捕获并打印消息。 通过此设置,当“getPage”失败时,控件会跳转到“printExceptions”,它会在不中断正常程序流程的情况下处理错误。 此外,我们可以创建其他效果,例如“流”,它生成潜在的无限和/或异步数据流,而不是仅仅依赖异常,从而使我们能够有效地处理大型数据集。 其他示例包括 Unison 语言中的“Each.toList”,我们在“each”函数内维护状态信息的同时映射范围,并相应地处理每个元素,而不会中断主流执行。 这些处理程序可以随意恢复功能,使代码更加灵活和高效。
From callsite Foo, I call out to a function with a known name, Bar, with one or more parameters. The runtime (or sufficiently smart compiler) searches upwards in scope, for a handler Baz that provides the function with that name. Baz's Bar is then called, with both the provided parameters, and, crucially, a function that is "the rest of Foo."
So, an implementation of Exception with effects would ignore the resume, and look something like:
But you could also write an "on error resume next" handler for Exception. Exceptions thrown with this handler would be equivalent to toss. (in real life you'd probably write a different effect, rather than re-using the Exception/throw effect): Breaking away from the Exception example, two cool examples are: And this one I'm just going to lift from the Unison documentation [1]: Note that this has the same semantics as: And it is possible to do this, because these resumable functions can be resumed an arbitrary number of times - it's up to the handler. They also can pass parameters back to the resume_func.Exceptions/hurl = exactly 0 resumptions toss = exactly 1 resumption effects = 0..many resumptions
[1]: https://share.unison-lang.org/@unison/base/code/releases/3.5...