如何使用细化来包装函数,以便不需要细化?

时间:2014-04-06 10:00:07

标签: function rebol rebol3

我正在尝试以通用的方式使用细化来包装函数,以便可以在不进行细化的情况下调用它们。例如,ARRAY-INITIAL size value而不是ARRAY/INITIAL size value

wrap: function [refined [path!] args [block!]] [
    function args compose [
        (refined) (args)
    ]
]

array-initial wrap 'array/initial [size value]

不太花哨。似乎一般工作,但如果你使用函数调用它,这有点奇怪:

>> n: 0 array/initial 4 does [++ n] 
== [10 11 12 13]

>> n: 10 array-initial 4 does [++ n]
== [10 10 10 10]

当我source时,我得到了这个:

>> source array-initial 
array-initial: make function! [[size value][array/initial size value]]

好的,那么发生的事情是函数在包装器中被调用并且调用的结果传递了...而不是函数。一种解决方法是使用get-word来避免评估:

>> array-initial-2: function [size value] [array/initial size :value]

>> array-initial-2: 10 array-initial-2 4 does [++ n]
[10 11 12 13]

但我一直在寻找一种通用方法。在不发生这种情况的情况下代理参数的最佳方法是什么?

3 个答案:

答案 0 :(得分:1)

我认为一般的方法是你必须考虑在函数参数中使用单词的方式以及传递给函数的方式。

wrap: func [
    'refined [path!]
    args [block!]
][
    func map-each arg args [
        either get-word? :arg [to word! arg] [:arg]
    ] compose [
        (refined) (
            map-each arg args [
                either lit-word? :arg [to get-word! arg] [:arg]
            ]
        )
    ]
]

这里有两个问题 - 定义函数的单词和传递给函数的单词。前者有两种主要形式:正常参数的 word!和文字参数的 lit-word!。在我们的规范中,如果我们有 get-word!参数,我们希望它们是普通参数并转换为 word!。当谈到传递参数时,我们又有两种形式: word!来评估参数, get-word!来传递单词指向的值。如果我们的规范处理 lit-word!,我们需要传递一个 get-word!作为字!将按字面传递。< / p>

希望一切都有意义!

无论如何,这是如何发挥作用的:

wrapped-foobar: wrap foo/bar ['literal evaluated :referred]

我们有三种类型,第一种允许你通过字面传递值 - 比如单词而不使用lit-words;第二个在通过前评估参数;第三个将传递引用的值 - 此表单允许您传递函数。你最终得到:

make function! [
    ['literal evaluated referred] [
        foo/bar :literal evaluated :referred
    ]
]

现在, array / initial 之类的内容已经开启:

array-initial: wrap array/initial [size :value]
n: 1
array-initial 4 does [++ n]

答案 1 :(得分:1)

这是一项非常有趣的练习,需要爱上这个。

事实证明你确实需要一个&#34; do reduce&#34;使用get-word参数包装函数...

仅在目前的R3:

unrefine: func [
  "Return an equivalent function with the given refinements wired in."
  refined [any-path! block!] "The function, with the refinements to include."
  /local ospec spec body found p s w b r
] [
  ospec: spec-of get first refined: to lit-path! :refined
  body: append copy spec: make block! length? ospec copy/deep [do reduce []]
  append/only body/3 :refined
  parse ospec [
    set s 0 1 string! (all [s append spec s])
    any [
      set w [word! | get-word! | lit-word!] (
        append spec :w
        append body/3 either word! = type? :w [reduce ['quote to get-word! w]][w])
      set b 0 1 block! (
        all [b append/only spec copy b])
      set s 0 1 string! (
        all [s append spec copy s])
    |
      /local to end
    |
      set r refinement! (
        p: any [p tail spec]
        if not found: find next refined r [append spec r])
      set s 0 1 string! (all [not found s append spec copy s])
      any [
        set w [word! | get-word! | lit-word!] (
          either found [p: insert p :w][append spec :w]
          append body/3 either word! = type? :w [reduce ['quote to get-word! w]][w])
        set b 0 1 block! (
          all [b either found [p: insert/only p copy b][append/only spec copy b]])
        set s 0 1 string! (
          all [s either found [p: insert p copy s][append spec copy s]])
      ]
    ]
  ]
  func spec body
]

答案 2 :(得分:0)

简单地说,你(a.k.a。me)如果不反映你正在包装的函数参数块,就无法实现这一点。没有其他办法。

如果函数使用了单词形式或参数的get-word形式,那么必须在包装器中镜像这种区别。请参阅此答案,了解:foo'foo形式参数之间的区别:

Why doesn't Rebol 3 honor quoted function parameters that are parenthesized?

Per @ rgchris的评论,你(a.k.a.I)需要做的是parse the argument block。一个正确的答案将包含执行此操作的代码,因此人们应该随意添加它。