World: r4wp
[Rebol School] REBOL School
older newer | first last |
Gregg 3-Oct-2012 [1072x3] | Easy enough to add sigils to make it special. I don't general go as far as a gensym approach for things like this. |
Yes. Too early for my brain here, but 'is known-word honored in the bind? e.g. "set with reduce (args)" | |
That is, 'with is special no matter what known-word you use, correct? | |
Ladislav 3-Oct-2012 [1075] | Marc, your "private variables" like 'with, _recur_ can be made more private not needing to use the PROtECT function, in fact. |
Gregg 3-Oct-2012 [1076] | Ah, no, I think I get it now. |
Steeve 3-Oct-2012 [1077] | I don't think you need 'with at all, you can throw back the new parameters as an argument of the throw function, like: >> throw/name reduce args 'recurse |
Ladislav 3-Oct-2012 [1078x2] | also, there is a problem with the result I think |
(I mean the function result) | |
MarcS 3-Oct-2012 [1080x2] | steeve: ooh, good point |
ladislav: ah yes, there is | |
Steeve 3-Oct-2012 [1082] | Here is a version with no locals, no temporary context, no shit and not tested ;-) rfunc: func [spec body][ func spec compose/deep [ forever [ set [(spec)] catch/name [ return (func spec body) (spec) ] 'recur ] ] ] recur: func [args][throw/name reduce args 'recur] |
MarcS 3-Oct-2012 [1083x2] | wow |
works well - full thing here: http://0branch.com/highlight/snippets/rfunc4.r | |
Steeve 3-Oct-2012 [1085x3] | to return a value and stop the function you need to use 'return instead of 'break |
I think | |
recur (Must be in tail position) -> not needed anymore | |
MarcS 3-Oct-2012 [1088] | well, it has to be a tail call |
Steeve 3-Oct-2012 [1089] | it's a tail call but it can be anywhere in the function body |
MarcS 3-Oct-2012 [1090x2] | so you couldn't do x + recur [ y ] |
sounds like we mean different things by 'tail position' | |
Steeve 3-Oct-2012 [1092x3] | it seems |
Yep, it seems | |
Yep, it seems | |
MarcS 3-Oct-2012 [1095] | i mean this: http://en.wikipedia.org/wiki/Tail_call |
Steeve 3-Oct-2012 [1096x2] | (lag) |
It's tail call recursion yes, but tail position usualy means "physically placed" at the tail (in our context, at the end of the body of the function) Anyway... | |
MarcS 3-Oct-2012 [1098] | not be pedantic, but i linked to that for the opening two sentences: In computer science, a tail call is a subroutine call that happens inside another procedure as its final action; it may produce a return value which is then immediately returned by the calling procedure. The call site is then said to be in tail position, i.e. at the end of the calling procedure. |
Steeve 3-Oct-2012 [1099] | Okay T_T |
MarcS 3-Oct-2012 [1100x2] | i've never heard tail position refer to last 'physical place' |
anyway, not important | |
Steeve 3-Oct-2012 [1102] | I just decided it would be a new paradigm :-) |
MarcS 3-Oct-2012 [1103x2] | heh, good stuff |
thanks again for the help | |
Steeve 3-Oct-2012 [1105] | No prob I was lazy on my couch |
Ladislav 3-Oct-2012 [1106] | Marc, to no pollute this group I posted a private conversation mentioning how to define a TAIL-CALL function using the function spec and how to handle the situation even if the function spec is "more complicated" than just a block of words. |
Steeve 3-Oct-2012 [1107] | It's Rebol School group here. Why would your post be a pollution ? I don't get it |
Ladislav 3-Oct-2012 [1108] | It is a bit long to my taste, but I can repost here if you prefer. Also, BTW, welcome to REBOL, Marc |
Steeve 3-Oct-2012 [1109] | Yes wellcome Marc. (Not really a beginner though) Yes Ladislav I've nothing against a long post here since it's related to the topic, or if you prefer you can use a copy/past service in the cloud. |
MarcS 3-Oct-2012 [1110] | thanks guys |
Ladislav 3-Oct-2012 [1111] | OK, this is the long version: tail-func: func [ { Define a recursive user function with the supplied SPEC and BODY. The function can use a special TAIL-CALL local function to perform a tail-recursive function call. } [catch] spec [block!] {Help string (opt) followed by arg words (and opt type and string)} body [block!] {The body block of the function} /local the-function tail-call context-word ] [ ; define a new 'tail-call local variable tail-call: use [tail-call] ['tail-call] ; bind the given BODY to "know" the 'tail-call variable body: bind/copy body tail-call ; find a local word in SPEC context-word: find spec word! if context-word [context-word: first context-word] ; define the TAIL-CALL function set tail-call func spec compose [ ( either context-word [ ; set parameters to the new arguments compose [set parameters values? (context-word)] ] [[]] ) throw/name none 'tail-call ] ; define the function the-function: throw-on-error [ func spec compose/deep [ (either context-word [context-word] [[]]) while [true] [ catch/name [ return do [(body)] ] 'tail-call ] ] ] if context-word [ ; get the function context context-word: bind? first second :the-function ; replace the context word in the function body by NONE change second :the-function none ; adjust the TAIL-CALL body ; replace the 'parameters word change/only at second get tail-call 2 bind first context-word context-word ] :the-function ] values?: func ['word] [second bind? word] |
Steeve 3-Oct-2012 [1112] | Hum Ok, I see the >> return do [(body)] as a nice optimization of my code. But for the rest, I'm not sure... |
Ladislav 3-Oct-2012 [1113] | example: safe: tail-func [x] [ if x > 20000 [print x exit] tail-call x + 1 ] |
Steeve 3-Oct-2012 [1114x3] | yeah I see that the purpose is to get ride of the block passing style of the arguments, but it looks not anymore as simple |
I think I included all your modifications Ladislav but shortly :-) rfunc: [spec body /local args][ args: to-block form first ( do second func spec compose [bind? (to-lit-word first find spec word!)] ) funct spec compose/deep [ recur: func spec [ throw/name reduce [(args)] 'recur ] forever [ set [(args)] catch/name [ return do [(body)] ] 'recur ] ] ] | |
I used a trick not well known. >> do second function! allow to execute a function without having to pass its arguments. | |
Kaj 3-Oct-2012 [1117] | Neat |
Steeve 3-Oct-2012 [1118x3] | Mmmmh, the function recur could be defined outside |
Should do the trick: rfunc: [spec body /local args][ args: to-block form first do second func spec compose [bind? (to-lit-word first find spec word!)] funct spec compose/deep [ recur: quote (func spec compose/deep [throw/name reduce [(args)] 'recur]) forever [ set [(args)] catch/name [return do [(body)]] 'recur ] ] ] | |
Notice the weird sequence >> to-block form first object! That is because the local context returned from a function is not well formed. If the specs of the function are [a [block!] /local b], it will return a strange objetc! where: >> first object! == [a /local b] So to correct its format, I do >> to-block form first object == [a local b] | |
Gregg 3-Oct-2012 [1121] | Marc, a simple naming question. Why did you choose 'recur instead of 'recurse? |
older newer | first last |