Metaprogramming Rebol中的级联

Metaprogramming Rebol中的级联,metaprogramming,rebol,Metaprogramming,Rebol,在Logo语言中,是一个将函数自身多次组合起来的过程(在函数语言中,它几乎类似于fold。 例如: add 4 add 4 add 4 5 --> cascade 3 [add 4 ?1] 5 == 17 2^8 --> cascade 8 [?1 * 2] 1 fibonacci 5 --> (cascade 5 [?1 + ?2] 1 [?1] 0) factorial 5 --> (cascade 5 [?1 * ?2] 1 [?2

在Logo语言中,是一个将函数自身多次组合起来的过程(在函数语言中,它几乎类似于
fold

例如:

   add 4 add 4 add 4 5  -->  cascade 3 [add 4 ?1] 5 ==  17
   2^8 -->  cascade 8 [?1 * 2] 1
   fibonacci 5 --> (cascade 5 [?1 + ?2] 1 [?1] 0)
   factorial 5 --> (cascade 5 [?1 * ?2] 1 [?2 + 1] 1)
多输入级联的通用符号,在徽标中:
(级联多少功能1开始1功能2开始2…)与:

级联返回?1的最终值

在Rebol中:

cascade1: func [howmany function1 start1] [....]      
cascade2: func [howmany function1 start1 function2 start2] [....]

如何在Rebol中编写cascade1和cascade2?

这里有一个Rebol中运行良好的
cascade
。它不能与
op一起使用数据类型——即
+
*
——但它将与
添加
相乘
一起工作。您可能需要查看以查看其他示例。我还没有时间写
cascade2

cascade: func [
    times [integer!]
    f [any-function!]
    partial-args [series!]
    last-arg
][
    expression: copy reduce [last-arg]
    repeat n times [
        insert head expression partial-args
        insert head expression get 'f
    ]
    expression
]
举个例子:

probe cascade 3 :add [4] 5
print cascade 3 :add [4] 5
将导致:

[make action! [[
        "Returns the addition of two values."
        value1 [scalar! date!]
        value2
    ]] 4 make action! [[
        "Returns the addition of two values."
        value1 [scalar! date!]
        value2
    ]] 4 make action! [[
        "Returns the addition of two values."
        value1 [scalar! date!]
        value2
    ]] 4 5]

17
[make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 1]

256

将导致:

[make action! [[
        "Returns the addition of two values."
        value1 [scalar! date!]
        value2
    ]] 4 make action! [[
        "Returns the addition of two values."
        value1 [scalar! date!]
        value2
    ]] 4 make action! [[
        "Returns the addition of two values."
        value1 [scalar! date!]
        value2
    ]] 4 5]

17
[make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 make action! [[
        "Returns the first value multiplied by the second."
        value1 [scalar!]
        value2 [scalar!]
    ]] 2 1]

256
通过将单词绑定到指定上下文(在本例中为函数的本地上下文)和函数,我得到:

cascade: func [  
    times
    template
    start 
] [
    use [?1] [
        ?1: start  
        template: compose [?1: (template)]  
        loop times bind template '?1  
        ?1
    ]  
]

cascade 8 [?1 * 2] 1
== 256
cascade 3 [add 4 ?1] 5
== 17  
val: 4
cascade 3 [add val ?1] 5
== 17



cascade2: func [
    times
    template1 start1
    template2 start2
    /local **temp**
] [
    use [?1 ?2] [ ; to bind only ?1 and ?2 and to avoid variable capture
        ?1: start1
        ?2: start2
        loop 
            times 
            bind 
                compose [**temp**: (template1) ?2: (template2) ?1: **temp**] 
                '?1
        ?1
    ]
]


 cascade2 5 [?1 * ?2] 1 [?2 + 1] 1
 == 120
 cascade2 5 [?1 + ?2] 1 [?1] 0
 == 8

我的答案使用REBOL3,但是可以在没有太多麻烦的情况下后端口到2。(我本应该在REBOL2中完成,但我的系统上没有REBOL2,而且很长时间没有使用它。)这完全实现了
cascade
(即,使用任意数量的“函数”),并以一种惯用的REBOL方式完成:它使用一个简单的DSL

cascade: funct [
  count [integer!]
  template [block!]
  /only "Don't reduce TEMPLATE"
  /local arg fun-block
][
  param-list: copy []
  param-number: 1
  arg-list: copy []
  fun-list: copy []
  template-rules: [
    some [
      copy fun-block block! (
        append param-list to word! rejoin ["?" ++ param-number]
        append fun-list fun-block
      )
      copy arg any-type! (
        append arg-list :arg
      )
    ]
    end
  ]
  unless only [template: reduce template]
  unless parse template template-rules [
    do make error! rejoin ["The template " mold/flat template " contained invalid syntax."]
  ]
  while [! tail? fun-list] [
    fun-list: change fun-list func param-list first fun-list
  ]
  fun-list: head fun-list
  loop count [
    temp-args: copy []
    for f 1 length? fun-list 1 [
      append/only temp-args apply pick fun-list f arg-list
    ]
    arg-list: copy temp-args
  ]
  first arg-list
]
使用它很简单:

print cascade 23 [[?1 + ?2] 1 [?1] 0]
这正确地给出了提问者链接的Logo
cascade
文档中给出的
cascade
示例之一的值
46368
。DSL的语法应该非常明显。它是一系列的块,后面是起始参数。除非使用
/仅
细化,否则外部块将缩小。块本身作为参数可以正常工作,例如

cascade 5 [[?1] [1 2 3]]
这是因为第一个块被解释为“函数”,第二个块被解释为起始参数,第三个块被解释为“函数”,依此类推,直到模板块用尽为止


据我所知,这是一个完整(相当优雅)的
cascade
实现。伙计,我爱瑞宝。很遗憾,这种语言没有流行起来。

我非常喜欢它,并将它添加到我的REBOL 3 Swiss army knife函数中,您可以在中找到。请注意,这些是REBOL 3模块。