Rebol:块字的动态绑定
在Rebol中,有像foreach这样的字,它允许在给定单词和一系列(例如foreach w [1 2 3] [print w]
)上执行“块参数化”。由于我发现语法非常方便(与传递func块相反),我想用它来处理懒惰列表上的我自己的单词,例如map/stream x s [... x ... ]
。 这个语法成语怎么叫?它如何正确实施?Rebol:块字的动态绑定
我正在搜索文档,但我找不到直接的答案,所以我试图自己实现foreach。基本上,我的实现分两部分。第一部分是一个函数,它将块中的特定单词绑定到给定值,并产生一个带有绑定单词的新块。
bind-var: funct [block word value] [
qw: load rejoin ["'" word]
do compose [
set (:qw) value
bind [(block)] (:qw)
[(block)] ; This shouldn't work? see Question 2
]
]
利用这一点,我实现的foreach如下:
my-foreach: func ['word s block] [
if empty? block [return none]
until [
do bind-var block word first s
s: next s
tail? s
]
]
我觉得这种方法很笨拙的(很可能是),所以我不知道如何这个问题可以更优雅的解决。无论如何,未来与我的玩意儿之后,我留下了两个问题:
在绑定-VAR,我不得不做一些包装中
bind [(block)] (:qw)
因为(block)
会“解散”。为什么?由于2(?),则绑定操作一个新块(由
[(block)]
表达式创建的),不是原来的一个传递给我-的foreach,与单独的绑定上执行的,所以我要在该操作。我错误地加了[(block)]
,它仍然有效。但为什么?
伟大的问题。 :-)在Rebol2和R3-Alpha中编写自己的自定义循环结构(现在,用Red重复的历史记录)有许多未解决的问题。 Rebol3开发人员已知这些类型的问题,并且considered blocking bugs。
(即Ren-C启动的原因是为了解决这样的顾虑。Progress has been made在several areas,虽然在写仍然有许多优秀的设计问题的时候,我会然而尝试只是回答下的历史假设你的问题。)
在绑定-VAR,我不得不做一些包装中
bind [(block)] (:qw)
因为(block)
会 “解散”。为什么?
这就是默认情况下COMPOSE的工作原理......它通常是首选行为。如果您不想要,请使用COMPOSE/ONLY,块不会拼接,但会按原样插入。
qw: load rejoin ["'" word]
您可以转换WORD! LIT-WORD!通过to lit-word! word
。您还可以将报价责任转移到您的样板,例如set quote (word) value
,并且完全避免qw
。
避免LOAD通常也是可取的,因为默认情况下它总是将东西带入用户上下文 - 因此它会丢失原始单词的绑定。做TO转换将保留原始WORD的绑定!在生成的LIT-WORD!中。
do compose [ set (:qw) value bind [(block)] (:qw) [(block)] ; This shouldn't work? see Question 2 ]
想必你的意思COMPOSE/DEEP这里,否则将无法工作...定期撰写嵌入式PAREN!小号咳嗽,GROUP!小号为[(block)]
不会被替代。
错误地,我加了
[(block)]
它仍然有效。但为什么?
如果你喜欢my-foreach x [1] [print x probe bind? 'x]
测试的bind?
的输出会告诉你,它必将进入“全局”用户上下文。
从根本上说,您没有任何制作对象!或USE来创建一个新的上下文来绑定身体。因此,所有你可能可能在这里做会剥离代码中的任何现有的绑定,并确保它们进入用户上下文。
但是原来你确实有一个USE,那你edited to remove。这是更正确的轨道上:
bind-var: func [block word value /local qw] [
qw: load rejoin ["'" word]
do compose/deep [
use [(qw)] [
set (:qw) value
bind [(block)] (:qw)
[(block)] ; This shouldn't work? see Question 2
]
]
]
你说得对怀疑的东西就是那副你是如何结合的。但是这个原因起作用的原因是因为你的BIND只重做了USE自己做的工作。 USE已经深入研究,确保任何字词绑定都被调整。所以,你可以省略完全绑定:
do compose/deep [
use [(qw)] [
set (:qw) value
[(block)]
]
]
被一个新块(由
[(block)]
表达式创建)上进行绑定操作,而不是原来一个传递给my-foreach
,与单独的绑定
让我们通过取出深度散步USE来调整您的代码,以证明您曾经认为想法的问题。我们将使用一个简单的MAKE OBJECT!而不是:
bind-var: func [block word value /local obj qw] [
do compose/deep [
obj: make object! [(to-set-word word) none]
qw: bind (to-lit-word word) obj
set :qw value
bind [(block)] :qw
[(block)] ; This shouldn't work? see Question 2
]
]
现在,如果你尝试my-foreach x [1 2 3] [print x]
你会得到你的怀疑......“X有没有价值”(假设你没有一些潜在的全局定义的X它拿起,这只是打印相同的潜在值3次)。
但是,为了让你充分对不起,你问:-),我会提及my-foreach x [1 2 3] [loop 1 [print x]]
实际上工程。这是因为虽然你说过去的约束不应该影响新的区块,但是这个COMPOSE只创建一个一个新的区块!最高级别是新的,在源材料中引用的“更深的”嵌入式模块将原有的材料别名:
>> original: [outer [inner]]
== [outer [inner]]
>> composed: compose [<a> (original) <b>]
== [<a> outer [inner] <b>]
>> append original/2 "mutation"
== [inner "mutation"]
>> composed
== [<a> outer [inner "mutation"] <b>]
因此,如果你所构成的结果变异BIND,它可以深刻影响一些您的来源的。
until [ do bind-var block word first s s: next s tail? s ]
在一般笔记的效率,你在你的循环的每个迭代运行撰写和绑定操作。无论这些问题的创新解决方案如何得到(Ren-C中有很多新技术影响你的问题),你仍然可能只想做一次,然后重复使用它迭代。
如果这是你感兴趣的话题,我绝对建议加入[讨论论坛](https://forum.rebol.info/t/separating-parse-rules-across-contexts/313/4 ?u = hostilefork)或[聊天室在这里](https://chat.stackoverflow.com/rooms/291/rebol)! – HostileFork
谢谢你的邀请(你的伟大的答案,你甚至发现我的编辑;))!我对这些事情非常感兴趣,所以我会加入你。再次感谢! – ftl