2014-11-14 3 views
2

В языке логотипа cascade - это процедура, чтобы составлять функцию с собой несколько раз (это почти как 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) 

Общие обозначения для нескольких входных каскада, в Логотип:
(каскад сколько function1 start1 function2 start2 ...) с:

function1 -> ?1 , 
function2 -> ?2 ... 

Каскад возвращает окончательное значение of 1.

В Rebol:

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

Как написать cascade1 и cascade2 в Rebol?

ответ

1

Вот несколько рабочих cascade в Rebol. Он не будет работать с типом данных op! - т. Е. +, * - но он будет работать с add и multiply. Вы можете посмотреть higher order functions script, чтобы посмотреть другие примеры. У меня не было времени, чтобы написать 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 

и

probe cascade 8 :multiply [2] 1 
print cascade 8 :multiply [2] 1 

будет приводить к :

[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 
2

С bind, что Связывает слова в указанном контексте (в данном случае локальный контекст функции), и compose функция, я получаю:

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 
2

Мой ответ использует REBOL 3, но может быть назад, без особых проблем. (Я бы сделал это в REBOL 2, но у меня нет REBOL 2 в моей системе и не использовал его в течение длительного времени.) Это реализует 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] 

Это правильно дает значение 46368 от одного из cascade примеров, приведенных в документации Логотип cascade связаны спрашивающего. Синтаксис DSL должен быть жестоким. Это серия блоков, за которыми следуют начальные аргументы. Внешний блок уменьшается, если не используется уточнение /only. Сам блок будет работать просто как аргумент, например.,

cascade 5 [[?1] [1 2 3]] 

Это происходит потому, что первый блок интерпретируется как «функция», вторая в качестве исходного аргумента, третья как «функция» и так далее, пока блок шаблона не будет исчерпан.

Насколько я могу судить, это полная (и довольно изящная) реализация cascade. Человек, я люблю REBOL. Какой позор этот язык не снимал.

+0

Мне это очень нравится, и я буду добавлять его в свой швейцарский армейский нож REBOL 3, который вы можете найти на https://github.com/Revolucent/rebol. Обратите внимание, что это модули REBOL 3. –