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,它就知道将单元格拆分为包含指向要执行的代码块的指针:
现在我本人同意你的提问方式。例如这是否向用户泄露了实现细节——谁不应该关心类型系统中的这个方面?
但不管怎样,有一个名为 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!
值是使用 func
、function
、does
和 has
构造函数创建的,并利用所谓的 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!
阵营。
在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,它就知道将单元格拆分为包含指向要执行的代码块的指针:
现在我本人同意你的提问方式。例如这是否向用户泄露了实现细节——谁不应该关心类型系统中的这个方面?
但不管怎样,有一个名为 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!
值是使用 func
、function
、does
和 has
构造函数创建的,并利用所谓的 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!
阵营。