Red的5种函数类型的区别,为什么要区分它们?

Differences between Red's 5 function types, and why does it distinguish them?

在Red中,有数据类型function!op!native!routine!action!的函数。它们之间有什么区别?据我所知,function! 用于用户自定义函数,op! 用于中缀运算符,routine! 用于 Red/System 中定义的函数,但为什么需要另外两个?

Red 基于 Rebol,因此具有相同的类型。

  • function!是red
  • 中定义的用户自定义函数
  • native! 是机器代码中的一个函数
  • op! 是一个用机器码写的中缀运算符
  • action!是机器码中的多态函数
  • routine!是从动态库导入的函数

虽然对于调用者来说,它可能看起来类似于 运行 一个主体为 BLOCK 的函数!代码到一个作为本机指令实现的代码......实现必须沿着不同的分支进行。

我不太清楚Red在编译情况下做了什么,Rebol2和Red的解释器情况是相似的。这些不同的类型实际上是大型 switch() 语句的一部分。如果它在描述 "function" 的单元格中查找并找到 TYPE_NATIVE,它就知道将单元格的内容解释为包含本机函数指针。如果找到 TYPE_FUNCTION,它就知道将单元格拆分为包含指向要执行的代码块的指针:

https://github.com/red/red/blob/cb39b45f90585c8f6392dc4ccfc82ebaa2e312f7/runtime/interpreter.reds#L752

现在我本人同意你的提问方式。例如这是否向用户泄露了实现细节——谁不应该关心类型系统中的这个方面?

但不管怎样,有一个名为 ANY-FUNCTION 的万能排版!:

>> any-function!
== make typeset! [native! action! op! function! routine!]

您可能会认为它是 "anything that obeys a function-like interface for calling"。然而,有一些复杂性,因为 OP!从左边获取第一个参数...所以从接口的角度来看,这确实是一个值得关注的问题。

总之……一个本地人! (主体作为本机代码构建到可执行文件中)与功能! (正文是解释或编译的红色代码块运行)只是一个区别。例程!是为与 DLL/library a la FFI that did not have a-priori knowledge of Red. An ACTION! is a very oversimplified attempt at what are called in other languages Generics 交互而构建的外观。一个OP!刚从左边获取第一个参数。

要点是,调用者可能对其中的每一个都感觉相同(OP 除外!),但实现必须做一些不同的事情。它知道做一些不同的事情的方式是通过值单元格中的类型字节。这就是 Rebol2 的做法——Red 相当密切地跟随 Rebol2——所以它也是这样做的。这意味着任何提供函数背后实现的新概念都需要新的数据类型,这可能不是最好的主意。

function!

正如您自己猜到的,function!s 是支持优化和类型检查的用户定义函数,并且还可以包含嵌入式文档字符串。

通常,function! 值是使用 funcfunctiondoeshas 构造函数创建的,并利用所谓的 spec 方言;但是,从理论上讲,没有什么能阻止您创建自己的构造函数或设计自己的规范格式。

还值得注意的是,function!完全支持反射。

op!

op!s 是其他 4 种函数之上的中缀包装器——它们在左边取一个值,在右边取一个表达式的结果,并且在求值期间它们也优先于其他函数。

op! 值仅限于两个参数,不支持细化,并且对反射的支持有限(例如,您不能使用 body-of 检查它们的主体)。

routine!

routines! 存在于 Red 和 Red/System(构建 Red 运行时的低级方言)的两个领域中。他们的规范是用 spec 方言写的,但他们的主体包含 Red/System 代码。哦,他们支持反射。

通常它们用于库绑定(如您提到的 SQL 库)、与运行时的交互或性能瓶颈(Red/System 是一种编译语言,因此重写性能-应用程序的关键部分作为一组 routine! 会给你带来显着的提升,但代价​​是强制编译。

native!

native!s 是用 Red/System 编写的函数(出于性能、简单性或可行性原因)并编译为本机代码(因此得名)。除了实施细节之外,不知道还能说些什么。 native! 不是很面向用户,所以您可能想研究 Red 的源代码以防您有任何疑问。

action!

action!s 是用 Red/System 编写的一组标准化函数(就像 native!s),每个数据类型实现(或继承)为它的 "method"。 action! 在某种意义上是多态的,它们在第一个参数上进行分派:

>> add 1 2%
== 1.02
>> add 2% 1
== 102%
>> append [1] "2"
== [1 "2"]
>> append "1" [2]
== "12"

在主流语言中,这通常看起来像 "1".append([2]) 或类似的东西。

action!s 和 native!s 之间的区别归结为设计选择:

  • 你可以有任意多的native!,但是action!s,为了效率,有一个固定大小的调度table(这意味着每个数据类型的最大 action! 数量是有限的;最小数量是两个:make [创建值] 和 mold [将值序列化为 string!]).

  • 逻辑上,action!s 围绕它们所属的数据类型组织在一个文件中,而 native!s 并不真正关心数据类型,并实现控制流、三角函数、集合运算等


巧合的是,就在最近我们有一个 similar discussion about action!s and native!s in our community chat, which you might want to read. I can also recommend to skim thru Rudolf Meijer's Red specification draft, and, of course, official reference documentation.

至于你问题中的"why" - 5种类型之间的区别只是一个实现细节,继承自Rebol。从逻辑上讲,他们都从概念的角度实现了你可能称之为 "function" 的东西,并属于 any-function! 阵营。