【问题标题】:Why does loop variable in repeat not work为什么重复中的循环变量不起作用
【发布时间】:2021-03-22 09:45:36
【问题描述】:

repeat 的循环变量可以像这样在它的块中使用:

>> b: func [x] [x + i]
== func [x][x + i]
>> repeat i 2 [print reduce append copy [b] [3]]
4
5

可以看到变量“i”被函数“b”使用了。

但是,在以下示例中,函数看不到循环变量“idx”。给出错误信息:

*** Script Error: idx has no value


Red []
map: function [a-func a-block][
result: [] args: [] clear result
either parse a-block [some block!][
  repeat idx length? a-block/1 [
    clear args
    foreach x a-block [append args to-block x/:idx]
    append result reduce append copy [a-func] args
    ]
   return result 
  ]
  [
   repeat idx length? a-block [
     append result to-block a-func a-block/:idx
     ]
   ]
]

map func [x y] [x + y - idx] [[1 2] [3 4]]

为什么第二个代码错了?以及如何让它发挥作用?

【问题讨论】:

    标签: red


    【解决方案1】:

    repeat的循环变量可以像这样在它的块中使用

    很遗憾,这在概念上是错误的。 块中不使用循环“变量”,它对函数的主体块和repeat都是“全局可见的”。

    >> repeat index 5 []
    >> index
    == 5
    

    从图表上看,这是 lambda → <idx in global context> ← repeat,而不是您可能认为的 lambda → repeat → <idx in repeat's "scope">

    但是,在以下示例中,函数看不到循环变量“idx”。

    这是因为您正在使用 function 构造函数,这使得 idx 单词在其上下文中是本地的,如下所示:

    >> function [][repeat index 3 []]
    == func [/local index][repeat index 3 []]
    

    相比之下,func(在您的第一个示例中使用)没有这样做。

    >> func [][repeat index 3 []]
    == func [][repeat index 3 []]
    

    也就是说,在这段代码中:

    map func [x y] [x + y - idx] [[1 2] [3 4]]
    

    idx 在你映射到块上的匿名函数中和idxmap 实现中是两个完全不同的“变量”,绑定到不同的上下文:一个到全局(在其中它没有价值,因此错误消息),另一个到本地(默认设置为none)。

    Red 的“范围”模型的机制(或者说完全没有它)是一个高级主题,但如果需要我可以详细说明。

    可以说它不依赖于传统的词法作用域(就像在大多数 Lisp 方言中一样),也没有严格意义上的变量。相反,它依赖于带有与命名空间(又名上下文)的绑定的符号值(又名单词),可以在运行时随意更改(参见下面示例中的bind)——有点像 f 表达式在Kernel 和较旧的 Lisps 中,或者可能是照应宏,其中 collect(另见下文)是一个很好的例子:注意它“捕获”keep 单词,从那时起,它指的是它的内部上下文,其中它被定义为append 的临时别名。查看source collect 输出以了解我的意思。


    这是map 的草图(从技术上讲,你的更像zip,但无论如何)给你一个潜在解决方案的提示。

    map: function [
        function [function!]
        series   [series!]
    ][
        spec:  spec-of :function ; ideally needs to be cleaned up
        step:  length? spec
        index: 1
        
        bind body-of :function 'index
        
        collect [
            foreach :spec series [
                keep/only do compose [(:function) (:spec)]
                index: index + step
            ]
        ]
    ]
    

    例子:

    >> map func [x] [reduce [index x]][a b c d]
    == [[1 a] [2 b] [3 c] [4 d]]
    >> map func [x y] [reduce [index x + y - index]][9 2 1 4]
    == [[1 10] [3 2]]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-16
      • 1970-01-01
      • 2014-01-20
      • 1970-01-01
      • 2020-04-15
      相关资源
      最近更新 更多