【问题标题】:How to make anonymous function work in Red/Rebol如何使匿名函数在 Red/Rebol 中工作
【发布时间】:2021-03-24 08:38:32
【问题描述】:

在 Red/Rebol 中,括号 () 可用于计算如下表达式:

>> (1 + 2 3 + 4)
== 7

但是,当我使用括号来评估匿名函数时,它会失败(请参阅以下代码)。为什么?以及如何让匿名函数工作?

>> (func [x y][x + y] 2 3)
== 3  ;;I think it should be 5.

PS:

>> do func [x y] [x + y]
== func [x y][x + y]
>> type? do func [x y] [x + y]
== function!
>> (do func [x y] [x + y]) 2 3
== 3  ;; why does this anonymous function still not work?
>> ((do func [x y] [x + y]) 2 3)
== 3  ;; This does not work too.

【问题讨论】:

    标签: red rebol3


    【解决方案1】:

    为什么?

    原因很简单:您的代码中没有匿名函数。如果您将其内容扫描为数据,它会变得更加明显:

    >> code: quote (func [x y][x + y] 2 3)
    == (func [x y] [x + y] 2 3)
    >> forall code [probe type? code/1]
    word!
    block!
    block!
    integer!
    integer!
    == integer!
    

    也就是说:func [x y][x + y]是一个word!后跟2个block!s,不是一个函数。但是,一旦评估,它将返回一个函数,其字面形式看起来完全相同。 func 本身就是一个创建另一个函数的函数(又名函数构造函数)。

    >> type? probe func [x y][x + y]
    func [x y][x + y]
    == function!
    

    在您的示例中,3 正是出于这个原因返回:解释器按顺序评估每个表达式;第一个表达式是一个函数调用func [x y][x + y],它接受两个块并返回一个函数;剩下的表达式是文字 23 ,它们对自己求值;最后一个表达式的结果总是以红色返回,所以你得到3。这种情况下的括号是多余的。

    >> 0 + 1 2 3
    == 3
    >> func [x y][x + y] 2 3
    == 3
    

    所以,如果你想匿名评估一个函数,你首先需要在函数构造函数的帮助下从 spec 和 body 块中创建一个 function! 值(例如funcfunctionhas、@ 987654339@ 或您自己编写的其他文件),然后才将其应用于参数。最常见的做法是do reduce 模式:

    >> do reduce [func [x y][x + y] 2 3]
    == 5
    

    reduce 计算块中的每个子表达式(func 创建一个 function!23 计算自己),然后 do 解释它(将匿名函数应用于两个论据)。

    这里有一些其他方法,以便您掌握这个概念:

    >> do compose [(func [x y][x + y]) 2 3]
    == 5
    >> do head insert [2 3] function [x y][x + y]
    == 5
    >> do reverse append [3 2] make function! [[x y][x + y]]
    == 5
    >> λ: func [spec body code][do compose [(func spec body) (code)]]
    == func [spec body code][do compose [(func spec body) (code)]]
    >> λ [x y][x + y][2 3]
    == 5
    

    至于为什么do func [x y][x + y] 会这样工作:这是设计使然,以防止可变参数函数调用。你可以阅读更多关于它的基本原理here

    Rebol/Red 中的所有函数都有一个固定的元数,并且只计算所需数量的表达式;返回调用站点并使用剩余参数的函数(例如在 Lisp 中)将违反此规则。

       ((lambda (x y)(+ x y)) 1 2)
    => 3
    

    作为一个历史奇闻,Rebol3 有一个 return/redo 改进,它允许函数做到这一点,由于我上面概述的原因,后来是 removed

    Rebol 系列中的评估是“分层的”,可以这么说:作为结果返回的值如果适用,则不会立即重新评估,而是需要从顶层调用额外传递到评估者(例如doreduce)。

    【讨论】:

    • func [x y] [x + y] 在一个块中只是块的三个元素。在成为函数之前,它们必须是 reduced。非常感谢这些详细的描述!
    • 我更新了我的查询。你想看看吗?谢谢
    • @lyl 当然。我已经扩展了我的答案以解决您的后记。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多