是否可以在纯REBOL中实现DO +功能?

时间:2014-12-24 05:19:57

标签: rebol

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

do :multiply 3 4
multiply 3 4

这两个陈述的效果相同。但我认为DO +函数会受到REBOL解释器的特殊处理,因为我不相信它可以在纯粹的DO(具有完全相同的语法)中实现REBOL,例如,

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

这是对的吗?

澄清

询问DO方言。这不是一个初学者"题。我非常非常了解REBOL的一般语法:Bindology(我在其上做过的一篇老博文),其同音性的含义,各种语言的含义以及其他所有内容。 (例如,here是我在REBOL中对徽标的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

当您可以在纯REBOL中编写自己的函数时,您已经回答了这个问题,在上面的示例中可以替换DO - 没有方言,块或任何其他修改 - 或解释为何无法完成。

3 个答案:

答案 0 :(得分:2)

您所看到的行为的原因是Rebol原生 DO 具体为this 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中找到,您可以在其中找到一些其他特殊控制位...例如隐藏的&#34;换行符&#34;标志:

// 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本机处理函数的方式是返回一种&#34;激活&#34;功能价值。但是,您无法使用用户代码中设置的此标志创建自己的值。设置标志的整个代码库中唯一的位置是DO本机中的这个片段。

看起来像是可以给予斧头的东西,因为APPLY在系统的定义中更干净地做到了这一点。

答案 1 :(得分: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?

答案 2 :(得分:0)

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

: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,所以不会发生任何事情。 唯一可行的方法是传递block! 1

>> 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但具有不同的含义。