World: r4wp
[Rebol School] REBOL School
older newer | first last |
Steeve 3-Oct-2012 [1119x2] | 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 [1121x2] | Marc, a simple naming question. Why did you choose 'recur instead of 'recurse? |
Ah, I love how AltMe optimizes code. :-) Thanks all. Very fun chat on this. | |
Steeve 3-Oct-2012 [1123] | I think Marc like to tease us with his naming convention |
Gregg 3-Oct-2012 [1124] | Now, there is this gloal RECUR func that is only usable inside RFUNC created funcs. While I'm still not very fond of the special KEEP func in COLLECT, should RECURSE be hidden/protected somehow? |
Steeve 3-Oct-2012 [1125] | Well it could be protected but see, you can also redefine standard words in every functions, at your own risk |
Gregg 3-Oct-2012 [1126] | Of course. For this, I'm also OK with the doc-string making the use clear. e.g. adding ONLY or MUST. |
Ladislav 3-Oct-2012 [1127x3] | I think I included all your modifications Ladislav but shortly :-) - well, your version still - misses error handling - uses the arg-block passing method (which is a matter of preference, i.e. some may prefer that) - uses REDUCE which does not "tolerate" certain argument types |
Ah, I love how AltMe optimizes code. - some "optimizations" are "at high cost" though. | |
however, I noticed that even my version would need to use one more THROW-ON-ERROR call | |
MarcS 4-Oct-2012 [1130x2] | morning all |
re: naming, borrowed from http://clojure.org/special_forms#toc12 | |
Ladislav 4-Oct-2012 [1132x2] | regarding the tail recursive functions: - there is also an implementation by Maarten Koopmans at rebol.org http://www.rebol.org/view-script.r?script=tailfunc.r&sid=l844jn - also, all above versions have some bugs worth correcting |
(that also seems to be the case of Maarten's code) | |
Steeve 4-Oct-2012 [1134] | Ladislav, - uses the arg-block passing method (which is a matter of preference, i.e. some may prefer that) No it uses the regular passing method, like yours. - misses error handling True, though it's not that hard to figure where to add some throw-on-error. "- uses REDUCE which does not "tolerate" certain argument types" Good catch |
Ladislav 4-Oct-2012 [1135] | No it uses the regular passing method, like yours. - aha, sorry, did not read the last version, or did not read it thoroughly enough. |
DocKimbel 4-Oct-2012 [1136] | Just a question about that very interesting thread on tail calls optimization: does at least one of the proposed solution support recursive function calls with refinements? (I had a quick look and it seems not, but I might have missed it). |
Ladislav 4-Oct-2012 [1137x3] | I put my last version to: http://www.rebol.org/view-script.r?script=tail-func.r Need to test it, but it should suport refinement calls as well. |
One more problem with all the versions mentioned except for my last version: - e.g the last Steeve's version "reserves" 'bind?, 'quote, 'forever, 'catch, 'set, 'return and 'do (and 'recur, but that is by design), while my last version does not "reserve" any word except for 'tail-call, which is by design. | |
(by "reserve" I mean that these words cannot appear in the function spec) | |
Steeve 4-Oct-2012 [1140x2] | Last version. - Any spec accepted but needs at least one parameter (can be just a local) rfunc: func [ [catch] spec [block!] body [block!] /local arg obj recur ][ throw-on-error [ if error? try [arg: to-lit-word first find spec any-word!][ make error! "rfunc needs at least one parameter." ] recur: func spec compose [throw/name bind? (:arg) 'recur] obj: catch/name [do second :recur] 'recur funct spec compose/deep [ recur: quote (:recur) forever [ set/any [(to-block form first obj)] second catch/name [ return do [(body)] ] 'recur ] ] ] ] |
Test case: safe: rfunc [x] [ if x < 5000 [recur x + 1] x ] safe 1000 == 5000 | |
Ladislav 4-Oct-2012 [1142] | re "any spec accepted", here are differences: >> safe: rfunc [throw] [if x < 20000 [recur x + 1]] ** Script Error: throw has no value ** Where: throw-on-error ** Near: rfunc [throw] [if x < 20000 [recur x + 1]] , while: >> safe: tail-func [throw] [if throw < 20000 [tail-call throw + 1]] >> safe 0 == none |
Steeve 4-Oct-2012 [1143] | Not really fair, you redefine the throw word and expect it to work as is ? Your function got the same problem on my pc, except it occurs at the execution time. ** Script Error: Cannot use path on integer! value ** Where: tail-call ** Near: throw/name none 'tail-cal or maybe you have a new version right now (Actually I have problems with Altme to synchronize with some recent posts I can't see all of them currenly) |
Ladislav 4-Oct-2012 [1144x5] | My version is this one: http://www.rebol.org/view-script.r?script=tail-func.r |
...and it works as posted above | |
(no "reserved words" at all, except that the 'tail-call word has got a special meaning as a function to make the tail call, however, it still *can* be redefined at the cost that the tail call cannot be made in such case since it is redefined) | |
...and it is not about "redefining the 'throw word", it is rather about allowing any word in the function spec... | |
Doc, regarding your question, see this example: >> safe2: tail-func [/local throw] [if throw < 20000 [tail-call/local throw + 1] throw] >> safe2/local 0 == 20000 | |
DocKimbel 4-Oct-2012 [1149x4] | Ladislav: thanks! |
Ladislav: would you be interested in improving the 'proxify function from the REBOL profiler I've built for Red project, it has the same kind of constraints as 'tail-call? The current code is a bit "rough", I don't have time to make a cleaner and simpler version of it. See code at: https://github.com/dockimbel/Red/blob/v0.3.0/red-system/utils/profiler.r | |
Also runtime performance is a big concern for such functions, so every little speed gain is good to take. | |
(sorry, I should have posted that in #Red group) | |
james_nak 4-Oct-2012 [1153] | I have a script that runs another script (via do) but when I launch it from an icon or through startup, the other script asks for permission to open a port. I've tried looking for some properties to change in the icon and setting secure to allow (which brings up its own requester). How do I do this? |
sqlab 4-Oct-2012 [1154] | see usage in the command level rebol.exe --secure allow in the link string should work wit most versions i |
james_nak 4-Oct-2012 [1155x2] | Thanks sqlab. I think that's my problem in setting that. The icon properties don't seem to let me do that. |
For now I just encapped the script and launch it as an .exe with no problems. Thanks anyway. | |
Steeve 4-Oct-2012 [1157] | Completly changed my mind. It's lot leasier to manage /recur as a refinement! - eg. safe/recur instead of recur - no words collision anymore (obviously /recur can't be used as a parameter). Also really short code rfunc: func [[catch] spec [block!] body [block!] /local ctx fun][ spec: append copy spec /recur ctx: bind? first second fun: throw-on-error [func spec [recur]] change second :fun compose/deep [ if (in ctx 'recur) [throw/name second (ctx) 'recur] while [true][ set/any [(bind to-block form first ctx ctx)] catch/name [ return do [(bind/copy body ctx)] ] 'recur ] ] :fun ] |
Ladislav 4-Oct-2012 [1158x6] | It's lot leasier to manage /recur as a refinement! - yes, that is an interesting idea |
Also, this implementation would behave differently in some interesting cases | |
Aha, maybe not... But still, it is interesting | |
However, I found another problem... | |
Which looks to be specific to this version. | |
What I specifically mean is this: f: rfunc [x] [if x = 2 [g/recur 3 5]] which does not look like making sense, although it can be written | |
Steeve 5-Oct-2012 [1164x3] | ;Go back to recur as a function. ;Still recur can't be used as a parameter, local or a refinement. ;This implementation is much more clean (no shitty compose/deep) and still very short. ;The collision of words is avoided by the use of singleton functions #[function!] ;I'm confident with this one. It could be the last one -_-; rfunc: func [[catch] spec [block!] body [block!] /local ctx args][ ctx: bind? first second throw-on-error [ ;* Temporary function created to retrieve parameters ;* and to get a new context for 'recur. ;* The context will remain alive (not GC'ed). func append copy spec /recur [recur] ] args: bind to-block form first ctx ctx ctx/recur: func spec reduce [ quote #[function! ['word] [throw/name second bind? word 'recur]] first args ;* may be 'recur if empty specs (still, it's ok) ] func spec reduce [ quote #[function! [args body][ while [true][set/any args catch/name [return do body] 'recur] ]] head remove back tail args ;* remove 'recur bind/copy body ctx ;* bound 'recur ] ] |
;Go back to recur as a function. ;Still recur can't be used as a parameter, local or a refinement. ;This implementation is much more clean (no shitty compose/deep) and still very short. ;The collision of words is avoided by the use of singleton functions #[function!] ;I'm confident with this one. It could be the last one -_-; rfunc: func [[catch] spec [block!] body [block!] /local ctx args][ ctx: bind? first second throw-on-error [ ;* Temporary function created to retrieve parameters ;* and to get a new context for 'recur. ;* The context will remain alive (not GC'ed). func append copy spec /recur [recur] ] args: bind to-block form first ctx ctx ctx/recur: func spec reduce [ quote #[function! ['word] [throw/name second bind? word 'recur]] first args ;* may be 'recur if empty specs (still, it's ok) ] func spec reduce [ quote #[function! [args body][ while [true][set/any args catch/name [return do body] 'recur] ]] head remove back tail args ;* remove 'recur bind/copy body ctx ;* bound 'recur ] ] | |
(Sorry for the double post) | |
Ladislav 5-Oct-2012 [1167x2] | Well, I do have a different suggestion, which might make sense.... |
The fact is that the CATCH/NAME+THROW/NAME pair is not ideal for this, but I do have a function which might be able to handle even the G/RECUR case. | |
older newer | first last |