Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] Rolling your own ideal looper: does Repeat still have a bug? Re:(6)

From: rebol:techscribe at: 31-Aug-2000 17:32

Hi Galt, it appears I didn't got all the emails in this thread. So the problem may already be solved. you wrote:
>Ladislav, > >That is an impressive For function! >your example of using >>a: [1 2] >>for s a tail a 1 [print s] >as a test is very amusing bug, looks >like an infinite loop on windows, just >keeps printing newlines without ever ending.
I guess you would rather see
>> for s a tail a 1 [print s]
1 2 2 I think that that's reasonable. The patched for version below does that. If you source the for function you'll see why for behaves as it does. The patched version corrects this and the other observed oddities. The results of running the patched version:
>> for s a next a -1 [print s]
== none
>> for s a next a 1 [print s]
1 2 2
>> for s a tail a 1 [print s]
1 2 2
>> for s a back tail a 1 [print s]
1 2 2 I added the following code to for: ;- the following line forces for to interpret ;- "tail of a series" as intended to mean "break at end of a series". if all [positive? bump tail? end ] [ end: back end ] ;- the following either any .. all .. combo catches errors resulting ;- from an end index that is higher than a start index with a ;- negative bump value, and also catches infinite loops that result ;- from passing an empty series either any [ empty? head end all [ if (negative? bump) [ op: :lesser?] op index? start index? end ] ] [ none ][ Note that I moved the expression if (negative? bump) [ op: :lesser?] into the all block of either's any block. The complete pathced for function follows: for: func [ "Repeats a block over a range of values." [catch throw] 'word [word!] "Variable to hold current value" start [number! series! money! time! date! char!] "Starting value" end [number! series! money! time! date! char!] "Ending value" bump [number! money! time! char!] "Amount to skip each time" body [block!] "Block to evaluate" /local result do-body op ][ if (type? start) <> (type? end) [ throw make error! reduce ['script 'expect-arg 'for 'end type? start] ] do-body: func reduce [[throw] word] body op: :greater-or-equal? either series? start [ if not same? head start head end [ throw make error! reduce ['script 'invalid-arg end] ] ;- the following line forces for to interpret ;- "tail of a series" as intended to mean "break at end of a series". if all [positive? bump tail? end ] [ end: back end ] ;- the following either any .. all .. combo catches errors resulting ;- from an end index that is higher than a start index with a ;- negative bump value, and also catches infinite loops that result ;- from passing an empty series either any [ empty? head end all [ if (negative? bump) [ op: :lesser?] op index? start index? end ] ] [ none ][ ;- we are dealing with a valid series while [op index? end index? start] [ set/any 'result do-body start start: skip start bump ] if (negative? bump) [ set/any 'result do-body start ] ] ] [ if (negative? bump) [op: :lesser-or-equal?] while [op end start] [ set/any 'result do-body start start: start + bump ] ] get/any 'result ]
>Just for kicks, I just tried this: >>> for s a back tail a 1 [print s] >1 2 >2 > >so that it stops at the last real position, >and that seemed to work, althout the expression >is more awkward and wordy! > >Your other example is this: >>> for s a next a -1 [print s] >1 2 > >which I am not sure I get. >This would never get to next a by skipping -1. >Either you have a typo here, or I missed the point. > >If this were integers, it would look like >for x = 1 30 step -1 > >>> for s a next a 1 [print s] >1 2 >2 > >What is the proper behavior of >>> for s a next a -1 [print s] >??? > >-Galt > >p.s. As far as the second-class vs. first-class values >goes, I am inclined to agree with you. There are some >fishy issues that don't seem entirely cooked. You are >right to bring them up for discussion. So far, however, >in the programs that have come up naturally in my >use of Rebol, I haven't been banging into these issues >alot. I have seen the errorhandling stuff e.g. try, disarm >seems like it's more awkward than it should be. >I could run smack into more of them at any moment, >though! > >p.p.s. I think the desire to share Rebol data and >objects across the net between two instances of rebol.exe, >or storing them and retrieving them later in native Rebol format, >will come up strongly in the near future. >Even the RebMail program might be a lot simpler if >you could just save your mail objects and reload later. >Having to create extra functions for converting from >Rebol to some other disk structure and then back >again is a pain. I think Rebol can do better. >It just needs to make a few new tricks available... > >>===== Original Message From "Ladislav Mecir" <[lmecir--geocities--com]> >>2. For loop. Here is my version working properly for series (just >>a minor improvement): >> >>Nobody uses For to traverse a series, I guess. OTOH, the >>implementation of For should be correct. >> >>; Example of incorrect behaviour: >>a: [1 2] >>for s a tail a 1 [print s] >>for s a next a -1 [print s] >> >>My correction: >> >>for: func [ >> {Repeats a block over a range of values.} >> [catch throw] >> 'word [word!] {Variable to hold current value} >> start [number! series! money! time! date! char!] {Starting >>value} >> end [number! series! money! time! date! char!] {Ending value} >> bump [number! money! time! char!] {Amount to skip each time} >> body [block!] {Block to evaluate} >> /local result do-body op cond >>][ >> if (type? start) <> (type? end) [ >> throw make error! reduce ['script 'expect-arg 'for 'end >>type? start] >> ] >> do-body: func reduce [[throw] word] body >> op: either positive? bump [:greater-or-equal?][ >> :lesser-or-equal? >> ] >> either series? start [ >> if not same? head start head end [ >> throw make error! reduce ['script 'invalid-arg end] >> ] >> cond: op index? end index? start >> while [cond] [ >> set/any 'result do-body start >> cond: op index? end (index? start) + bump >> start: skip start bump >> ] >> ] [ >> while [op end start] [ >> set/any 'result do-body start >> start: start + bump >> ] >> ] >> get/any 'result >>] >> >
;- Elan [ : - ) ] author of REBOL: THE OFFICIAL GUIDE REBOL Press: The Official Source for REBOL Books http://www.REBOLpress.com visit me at http://www.TechScribe.com