View in color | License | Download script | History |
30-Apr 15:49 UTC
[0.055] 13.588k
[0.055] 13.588k
tailfunc.rREBOL [
Title: "Tail recursion"
Date: 14-Nov-2001/15:58:27+1:00
Version: 1.0.0
File: %tailfunc.r
Author: "Maarten Koopmans"
Purpose: {Provides transparent tail recursive functions with refinement transferral. Source code 4 gurus only}
Email: %m--koopmans2--chello--nl
Web: http://www.vrijheid.net
library: [
level: 'advanced
platform: 'all
type: [Tool function]
domain: 'UI
tested-under: none
support: none
license: none
see-also: none
]
]
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 'local])]
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
]
;some samples
rec-fun: tail-func [x [integer!]][x: x + 1 print x rec-fun x]
rec-fun2: tail-func [x /y z]
[
x: x + 1
either y
[ print [ x z ] rec-fun2 x]
[ print x rec-fun2/y x x ]
] Notes
|