5

我试图以一种通用的方式用改进来包装函数,这样就可以在没有改进的情况下调用它们。例如,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]

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

4

3 回答 3

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

这里有两个问题——定义函数的词和传递给函数的词。前者有两种主要形式:字!对于正常的论点和点燃的词!对于文字参数。在我们的规范中,如果我们有get-word!参数,我们希望它们是普通参数并转换为单词!. 当涉及到传递参数时,我们同样有两种形式:单词!评估论点和获取词!传递单词指向的值。如果我们的规范处理一个字!,我们需要传递一个get-word!一句话将按字面意思传递。

希望这一切都说得通!

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

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]
于 2014-04-06T11:43:02.057 回答
1

这是一个令人着迷的练习,一定很喜欢。

事实证明,您实际上需要一个“do reduce”来包装带有 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
]
于 2015-01-24T15:02:55.797 回答
0

简而言之,如果不反映您正在包装的函数参数块,您(又名我)将无法完成此操作。没有其他办法。

如果函数使用参数的 lit-word 形式或 get-word 形式,则该区别必须反映在您的包装器中。:foo有关参数的和'foo形式之间的区别的解释,请参见此答案:

为什么 Rebol 3 不尊重带括号的引用函数参数?

根据@rgchris 的评论,您(又名我)需要做的是解析参数 block。正确的答案将包含执行此操作的代码,因此人们应该随意添加。

于 2014-04-30T07:21:01.213 回答