Hey all,
See below a tail-func function: it allows you to define a tail-recursive
function *with refinements*.
Refinement transferral is correct even if refinements change in a recursive
call.
You can also use it as a drop-in replacement for normal funcs, provided that
they don't do an almost tail-recursive thing as in:
f: tail-func [x] [ 1+ f x]
OTOH, this works:
f: tail-func [x /y z]
[
x: x + 1
either [ y ]
[ print [ "x: " x "z: " z] f x
[ print [ "x: " x ] f/y x x ]
]
and so do all other func definitions.
The trick is that I use an extended use context as a kinda stack frame to
implement goto like behaviour.
Also posted to the reb in the script libs as tailfunc.r
Enjoy,
Maarten
REBOL []
tail-func: func
[
{Returns a function that handles tail-recursion transparently.}
args [block!] body [block!]
/local meta-func meta-spec meta-body p1 p2
]
[
meta-spec: append/only copy [] args
meta-body: append/only copy [] body
;matches refinements and copies refinements to our command
p1: [ set r refinement!
(either get bind to-word r 'comm
[
append comm mold r
ref-mode: on
]
[ ref-mode: off ]
)
]
;matches words and copies their values to the statement if ref-mode = on
p2: [ set w word! (if ref-mode [ append/only statement get bind to-word w
'comm])]
meta-func: copy
[
;The use context is accessible from the wrapper function that
;eliminates tail recursion. It plays the role of a stack frame
;ti implement a goto like behaviour in case of tail recursion
use [ _*loop-detected _*myself _*innerfunc _*loops _*myspec _*myspec2
_*mycall]
[
;some static initialization of the use context varaiables
_*loops: 0
_*loop-detected: false
_*mycall: copy []
_*innerfunc: func (meta-spec) (meta-body)
_*myspec: copy first :_*innerfunc
_*myspec2: append copy _*myspec [/local ref-mode p1 p2 r w
comm statement
ret]
insert/only _*myspec2 [catch]
;The function that is returned from the use context
_*myself: func _*myspec2
[
;How deep in a loop am I?
_*loops: _*loops + 1
;These parse rules extract how I am called
;(which refinements and so)
p1: [(p1)]
p2: [(p2)]
ref-mode: on
;Ourt initial call
comm: copy {_*innerfunc}
;Our initial statement
statement: copy []
;Generate our statement and call
parse _*myspec [ any [ p1 | p2 ]]
insert statement to-path comm
;Copy it in the use context so it survives
;a loop (_*mycall is the 'goto args)
_*mycall: copy statement
if _*loops = 2
[
_*loops: 1
_*loop-detected: true
return
]
;Until we are no longer in loop-detection mode
until
[
_*loop-detected: false
set/any 'ret do bind _*mycall '_*loops
not _*loop-detected
]
;set/any 'ret pick ret 1
;Use context cleanup
_*loops: 0
_*loop-detected: false
_*mycall: copy []
;return our value
return get/any 'ret
];_*myself: func ...
];use context
];meta-func
;return our function....
do compose/deep meta-func
]
--
To unsubscribe from this list, please send an email to
[EMAIL PROTECTED] with "unsubscribe" in the
subject, without the quotes.