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]]
为什么第二个代码是错误的?以及如何让它发挥作用?
答案 0 :(得分: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
在块上映射的匿名函数和 idx
实现中的 map
是两个完全不同的“变量”,绑定到不同的上下文:一个到全局(在它没有值,因此是错误消息),另一个是本地(默认设置为 none
)。
Red 的“范围界定”模型的机制(或者说完全没有)是一个有点高级的话题,不过如果需要,我可以详细说明。
可以说它不依赖于传统的词汇范围(如大多数 Lisp 方言),也没有严格意义上的变量。相反,它依赖于符号值(又名单词),这些值带有与命名空间(又名上下文)的绑定,可以在运行时随意更改(参见下面示例中的 bind
)——有点像 f - 表达式在 Kernel 和较旧的 Lisps 中,或者可能是照应宏,其中 collect
(也见下文)是一个主要示例:注意它“捕获”keep
单词,从那时起on 指的是它的内部上下文,它被定义为 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]]