【问题标题】:Is it possible to implement DO + function in pure REBOL?是否可以在纯 REBOL 中实现 DO + 功能?
【发布时间】:2014-12-24 05:19:57
【问题描述】:

DO 后跟一个函数时,会执行该函数,并且根据给定函数的数量将剩余的值作为参数使用,例如,

do :multiply 3 4
multiply 3 4

这两个语句的效果相同。但我认为DO + 函数受到 REBOL 解释器的特殊处理,因为我不相信在纯 REBOL 中实现你自己的DO (使用完全相同的语法)是可能的,例如,

perform: func [f [any-function!]] [
    ; What goes here?
]

这是正确的吗?

澄清

不是询问DO 方言。这不是一个“初学者”的问题。我非常非常了解 REBOL 的一般语法:Bindology(我在上面写的一篇旧博文)、它的同音性的含义、单词的各种风格等等。 (例如,here 是我在 REBOL 中对 Logo 的 cascade 的实现。虽然我在这样做,但为什么不将我的 Vim syntax plug-in 插入 REBOL。)

我在问一些更微妙的问题。我不确定如何比我已经更清楚地表达它,所以我会请你更仔细地阅读我原来的问题。我想实现一个功能,像DO,具有以下能力:

do :multiply 3 4
double: func [n] [n * 2]
do :double 5

请注意语法do :doubledo :multiply 如何在其后使用适当数量的REBOL 值。 这是理解我在问什么的关键。据我所知,编写自己的 REBOL 函数是不可能的,可以DO this。

如果您可以用纯 REBOL 编写自己的函数,该函数可以替代上述示例中的 DO(无需方言、块或任何其他修改),您就已经回答了这个问题,或者解释其原因做不到。

【问题讨论】:

标签: rebol


【解决方案1】:

您所看到的行为的原因是专门针对 Rebol 原生 DOthis line of code

/***********************************************************************
**
*/  REBNATIVE(do)
/*
***********************************************************************/
{
    REBVAL *value = D_ARG(1);

    switch (VAL_TYPE(value)) {

       /* ... */

    case REB_NATIVE:
    case REB_ACTION:
    case REB_COMMAND:
    case REB_REBCODE:
    case REB_OP:
    case REB_CLOSURE:
    case REB_FUNCTION:
        VAL_SET_OPT(value, OPTS_REVAL); /* <-- that */
        return R_ARG1;

此 OPTS_REVAL 可以在 sys-value.h 中找到,您可以在其中找到一些其他特殊控制位...例如隐藏的“换行符”标志:

// Value option flags:
enum {
    OPTS_LINE = 0,  // Line break occurs before this value
    OPTS_LOCK,      // Lock word from modification
    OPTS_REVAL,     // Reevaluate result value
    OPTS_UNWORD,    // Not a normal word
    OPTS_TEMP,      // Temporary flag - variety of uses
    OPTS_HIDE,      // Hide the word
};

所以 DO 原生处理函数的方式是返回一种“激活的”函数值。但是您不能在用户代码中设置此标志来创建自己的值。整个代码库中唯一设置标志的地方是 DO native 中的这个 sn-p。

它看起来像是可以被砍掉的东西,因为 APPLY 在系统定义范围内做得更干净。

【讨论】:

  • 这是我怀疑的。我应该去看看源头。我以前研究过。
  • 我希望看到它被删除以保持一致性或(作为实验)扩展,例如func perform [[activated] f [any-function!]] [:f],其中activated 属性告诉解释器做什么。我可以看到很多有趣的语法可能性,但我也看到了很多问题。 (主要是很难理解的代码。同音性已经足够抽象,无需添加类似的东西。不过,看看能做什么会很有趣。)
【解决方案2】:

是的,在 Rebol 3 中:

>> perform: func [f [any-function!]] [return/redo :f]
>> perform :multiply 3 4
== 12

>> double: func [n] [n * 2]
>> perform :double 5
== 10

您可能会觉得阅读起来很有趣:Why does return/redo evaluate result functions in the calling context, but block results are not evaluated?

【讨论】:

  • 出于历史目的,值得指出的是,尽管由于存在问题,该改进已从当前版本中删除。见CC #2121
【解决方案3】:

这是一个很好的问题,我会尽我所能解释它。 上面的两个陈述实际上是相同的,但值得深入了解正在发生的事情。

:word 语法称为get-word!,相当于写成get 'word。所以另一种写法是

do get 'multiply 3 4

multiply 只是 Rebol 的另一个 word!

do 方言是 Rebol 解释器使用的默认方言。

如果您想实现自己的do 版本,您需要自己评估您的代码/数据,而不是使用do。这是一个简单的例子:

perform: func [ code [block!]] [ if equal? code [ 1 ] [ print "Hello" ] ]

这将perform 定义为一个接受代码块的函数。如果传递的代码是整数1,则它所期望的“语言”或方言是微不足道的,因为语法只是执行一个操作(打印“hello”)。

如果这被称为 perform [ multiply 3 4 ] 因为code 不等于1,所以什么都不会发生。 它做某事的唯一方法是传递一个包含1block!

>> perform [ 1 ]    
Hello

稍微扩展一下:

perform: func [ code [block!]] [ if equal? code [ multiply 3 4 ] [ 42 ] ]

会给我们一个perform,它的行为非常不同。

>> perform [ multiply 3 4 ]
== 42

您可以轻松编写自己的do 来评估您的方言,但如果您直接运行它,那么您已经在do 方言中运行,因此您需要调用某种函数来引导您自己的方言。

这种在方言之间跳转是编写 Rebol 代码的正常方式,parse 方言就是一个很好的例子

parse [ 1 2.4 3 ] [ some number! ]

它有自己的语法,甚至可以重复使用现有的do 方言词,例如skip,但具有不同的含义。

【讨论】:

  • 我不确定我是否回答了您关于确切语法的所有问题,但请访问我们的聊天室,希望我们能解释一下chat.stackoverflow.com/rooms/291/rebol-and-red
  • 虽然这是对初学者的 REBOL 概念的很好解释,但我远非如此。 (例如,here 是我在 REBOL 中对 Logo 的 cascade 函数的实现。)不幸的是,您完全错过了我的问题的重点,这比您意识到的要微妙一些。
  • 我希望,@johnk,我们可以将您的出色答案转移到另一个更适用的问题。它解释了初学者可能想知道的许多事情,但正如您所见,这不是我所要求的答案。
  • 我下次一定会更仔细地阅读问题!干杯
猜你喜欢
  • 2020-03-24
  • 1970-01-01
  • 2014-10-14
  • 2016-10-27
  • 2022-01-21
  • 1970-01-01
  • 2013-07-28
  • 2012-12-27
  • 2015-08-04
相关资源
最近更新 更多