The last part was about the behaviour of Rebol Functions. The
present behaviour can be called "Computed Quasi Static Binding
with Dynamic Recursion Patch."

Interesting about the "Computed Quasi Static Binding" is, that it
can handle recursion even without the "Dynamic Recursion Patch",
as can be
seen in the next model:

; Model of Context creation:
; **************************

make-context: func [
    {create a Context containing given Words}
    words [block!]
    /local context-init result
] [
    ; this implementation has got an issue:
    ; the created Context always contains 'Self
    words: difference/only words [self]
    context-init: make block! 4 * length? words
    foreach word words [
        append context-init to set-word! word
        append context-init none
        append context-init :unset
        append context-init to lit-word! word
    ]
    result: make object! context-init
    unset in result 'self
    result
]

{
    The following version of Same-context? uses Make-context to
look more natural:
}

same-context?: func [
    {find out, if the given Words are the Words of the same
Context}
    word1 [word!]
    word2 [word!]
] [
    either special-context? word2 [
        special-context? word1
    ] [
        same? word1 bind in make-context reduce [word1] word1
word2
    ]
]

; Model of CQSB function:
; *****************************

cqsb-function!: make object! [
    ; every cqsb function has got a Spec attribute
    spec: none
    ; every cqsb function has got a Body attribute
    body: none
]

; Model of CQSB Func function:
; *********************************

cqsb-func: func [
    {create a CQSB-function!}
    spec [block!]
    body [block!]
    /local spec-too body-too
] [
    spec-too: copy spec
    body-too: copy/deep body
    make cqsb-function! [
        spec: spec-too
        body: body-too
    ]
]

; Model of the CQSB function body execution:
; *******************************************

; the same as for Sim-function
do-body: func [body] [do body]

; Model of CQSB function Evaluation:
; ***********************************

cqsb-evaluate: func [
    {evaluate a sim-function contained in a block with its
arguments}
    block [block!]
    /local cqsb-f new-context actual-values
] [
    ; evaluate the arguments
    block: reduce block
    ; the executed cqsb-function is first
    cqsb-f: first block
    ; create a new Context
    new-context: make-context cqsb-f/spec
    ; give new Context words the supplied values
    set/any bind/copy cqsb-f/spec in new-context 'self next block
    ; execute the function body and return the result
    return do-body bind/copy cqsb-f/body in new-context 'self
]

; Some tests:
; **************

blk: copy []
probeblk: func [] [
    prin mold blk
    prin ": "
    print mold reduce blk
]
recfun: cqsb-func [x] [
    append blk 'x
    either x <= 1 [
        probeblk
    ] [
        cqsb-evaluate [recfun x - 1]
    ]
]
cqsb-evaluate [recfun 3]
probeblk

{
    Results:

>> cqsb-evaluate [recfun 3]
[x x x]: [3 2 1]
>> probeblk
[x x x]: [3 2 1]


This shows, that "Pure CQSB" looks better than "CQSB with DRP".
Recursion is not the only case, where "Pure CQSB" looks better.
For another example, see this:

}

f: func [x] ['x]
y: f 1
z: f 2
get y

{
    Results:

>> get y
== 2

While Pure CQSB yields:
}

f: cqsb-func [x] ['x]
y: cqsb-evaluate [f 1]
z: cqsb-evaluate [f 2]
get y

{
    and the results:

>> get y
== 1

But, as always, everything has got its price. Pure CQSB is more
demanding (every call needs a new Context/Binding). Moreover, the
above implementation is not GC-bug proof.
}

to be continued...

Reply via email to