代码之家  ›  专栏  ›  技术社区  ›  ftl

Rebol:块字的动态绑定

  •  4
  • ftl  · 技术社区  · 7 年前

    在Rebol中,有这样的词 foreach公司 foreach w [1 2 3] [print w] . 因为我发现这种语法非常方便(与传递func块相反),所以我想将其用于我自己在惰性列表上操作的单词,例如 map/stream x s [... x ... ] . 这个语法成语叫什么?如何正确实施?

    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
        ]
    ]
    

    我发现这种方法相当笨拙(可能是这样),所以我想知道如何更优雅地解决这个问题。无论如何,在提出我的发明后,我只剩下两个问题:

    1. 在bind var中,我必须在 bind [(block)] (:qw) 因为 (block) 会“溶解”。为什么?

    2. 因为(?)在2中,绑定操作在新块上执行(由 [(block)] [(块)] 它仍然有效。但是为什么呢?

    1 回复  |  直到 7 年前
        1
  •  4
  •   HostileFork says dont trust SE    7 年前

    好问题.:-)在Rebol2和R3 Alpha中编写自己的自定义循环构造(现在,历史用Red重复)有许多未解决的问题。Rebol3开发人员和 considered blocking bugs .

    (原因是: Ren-C 是为了解决这些问题。 Progress has been made 在里面 several areas 尽管在撰写本文时,仍然存在许多突出的设计问题。然而,我将尝试在历史假设下回答您的问题。)

    在bind var中,我必须在 bind [(block)] (:qw) 因为 (block)

    这就是默认情况下COMPOSE的工作方式。。。这通常是人们的首选行为。如果不需要,请使用COMPOSE/ONLY,块将不会拼接,而是按原样插入。

    qw: load rejoin ["'" word]

    你可以转换文字!到LIT-WORD!通过 to lit-word! word . 您还可以将报价责任转移到样板文件中,例如:。 set quote (word) value ,并避免 qw 总共

    do compose [
        set (:qw) value
        bind [(block)] (:qw)
        [(block)] ; This shouldn't work? see Question 2
     ]
    

    想必你在这里指的是撰写/深度,否则这根本不起作用。。。用正则构造嵌入参数!s GROUP! s 对于 [(block)]

    我错加了一句 [(块)] 它仍然有效。但是为什么呢?

    my-foreach x [1] [print x probe bind? 'x] 输出 bind? 将向您展示它被绑定到“全局”用户上下文中。

    基本上,你没有任何MAKE对象!或用于创建新的上下文以将身体绑定到其中。因此你可以 在这里要做的是剥离x代码中的任何现有绑定,并确保它们进入用户上下文。

    但最初你 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
            ]
        ]
    ]
    

    你有理由怀疑你的捆绑方式有问题。但这之所以有效,是因为您的绑定只是重复使用本身所做的工作。使用已经很深的行走来确保调整了任何单词绑定。因此,您可以完全忽略绑定:

    do compose/deep [
        use [(qw)] [
            set (:qw) value
            [(block)]
        ]
    ]
    

    [(块)] 表达式),而不是传递给的原始表达式 my-foreach ,具有单独的绑定

    让我们通过使用深度行走来调整代码,以演示您遇到的问题 想法 你有。我们将使用一个简单的MAKE对象!相反:

    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]] 事实上 作品 . 这是因为,虽然你说过去的绑定不应该影响新块是正确的,但这种组合只会创建 新建块!。最顶层是新的,源材质中引用的任何“更深”嵌入块都将是原始材质的别名:

    >> 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>]
    

    因此,如果对合成的结果进行变异绑定,它可能会对 一些 你的消息来源。

    until [
        do bind-var block word first s
        s: next s 
        tail? s
    ]
    

    为了提高效率,在循环的每次迭代中都要运行COMPOSE和BIND操作。无论这些问题的新解决方案多么富有创意 (Ren-C中有很多新技术会影响你的问题) ,您可能仍然只想做一次,并在迭代中重用它。