【问题标题】:Differences between Red's 5 function types, and why does it distinguish them?Red 的 5 种函数类型之间的区别,为什么要区分它们?
【发布时间】:2019-04-24 14:18:52
【问题描述】:

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

【问题讨论】:

    标签: rebol red


    【解决方案1】:

    function!

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

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

    另外值得注意的是function!s 完全支持反射。

    op!

    op!s 是其他 4 种类型函数之上的中缀包装器 - 它们在左侧采用一个值,在右侧采用表达式的结果,并且在评估期间它们也优先于其他函数。

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

    routine!

    routines! 存在于 Red 和 Red/System(构建 Red 运行时的底层方言)两个领域。他们的规范是用 spec 方言编写的,但他们的正文包含红色/系统代码。哦,他们支持反射。

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

    native!

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

    action!

    action!s 是用 Red/System 编写的一组标准化函数(就像 native!s),每个数据类型都将其实现(或继承)作为其“方法”。 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 之间的区别归结为设计选择:

      1234563最小数量为两个:make [创造价值] 和 mold [将价值序列化为 string!])。
    • 从逻辑上讲,action!s 在一个文件中围绕它们所属的数据类型进行组织,而native!s 并不真正关心数据类型,而是实现控制流、三角函数、集合上的操作,等等


    巧合的是,就在最近我们的社区聊天中有一个关于action!s 和native!s 的similar discussion,您可能想阅读一下。我还可以推荐浏览一下 Rudolf Meijer 的 Red specification 草稿,当然还有 official reference documentation

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

    【讨论】:

      【解决方案2】:

      对于调用者来说,运行一个主体为 BLOCK 的函数可能看起来很相似!将代码转换为作为本机指令实现的代码...实现必须走不同的分支。

      我不确切知道 Red 在编译案例中做了什么,Rebol2 和 Red 的解释器案例是相似的。这些不同的类型实际上是大 switch() 语句的一部分。如果它查看描述“函数”的单元格并找到 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!]
      

      您可能会将其视为“任何遵循类似函数的接口进行调用的东西”。然而,有一些复杂性,作为 OP!从左边获取它的第一个参数...所以从接口的角度来看,这确实是一个值得关注的问题。

      无论如何……一个本地人! (主体作为本机代码构建到可执行文件中)与功能! (body 是一段由解释或编译运行的 Red 代码)只是一个区别。例行公事!是一个外观,用于与不具备 Red 先验知识的 DLL/库a la FFI 进行交互。一种行为!是对其他语言Generics 的一种非常简化的尝试。一个OP!只是从左边获取它的第一个参数。

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

      【讨论】:

      • 感谢您的回答。
      • @nickkoro 我觉得我回答了你最初的问题(“为什么 Red 有 5 种不同类型的函数?”)比你最终接受的那个更好,它把答案添加为脚注(并掩盖了OP的难度!将这些放在一起时)。但这是基于我的阅读。如果他的答案是您正在寻找的答案,那么我更改了您的问题的标题以匹配他实际回答的内容——在哪里列出函数类型并添加“为什么”作为脚注是合适的。
      • 你说得对,标题误导了,我改一下。我正在寻找差异的概述(恕我直言,接受的答案涵盖的最好)为什么做出这个决定(你已经涵盖)。
      【解决方案3】:

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

      • function!是用户定义的函数,用红色定义
      • native! 是机器码中的函数
      • op! 是用机器码编写的中缀运算符
      • action! 是机器码中的多态函数
      • routine!是从动态库中导入的函数

      【讨论】:

      • 感谢您的回复,但我仍然不明白native!routine! 之间的区别。事实上,您可以自己编写routines!(已经为小型私有 mysql 库做到了),并且不必导入它们。此外,afaik 您可以在解释为红色时定义 op!。 “多态函数”是什么意思?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-08-10
      • 2012-03-20
      • 2014-06-24
      • 1970-01-01
      • 2010-10-18
      • 2019-02-05
      • 2014-03-20
      相关资源
      最近更新 更多