3

I attempted to write a C-style for-loop in REBOL:

for [i: 0] [i < 10] [i: i + 1] [
    print i
]

This syntax doesn't appear to be correct, though:

*** ERROR
** Script error: for does not allow block! for its 'word argument
** Where: try do either either either -apply-
** Near: try load/all join %/users/try-REBOL/data/ system/script/args...

Does REBOL have any built-in function that is similar to a C-style for loop, or will I need to implement this function myself?

The equivalent construct in a C-like language would look like this, but I'm not sure if it's possible to implement the same pattern in REBOL:

for(i = 0; i < 10; i++){
    print(i);
}
Anderson Green
  • 30,230
  • 67
  • 195
  • 328

5 Answers5

6

Because of the tag, I'll assume this question pertains to Rebol 3.

Proposed "CFOR" for Rebol 3

For Rebol 3, there is a proposal (which got quite a bit of support) for a "general loop" very much along the lines of a C-style for and therefore currently going under the name of cfor as well: see CureCode issue #884 for all the gory details.

This includes a much refined version of Ladislav's original implementation, the current (as of 2014-05-17) version I'll reproduce here (without the extensive inline comments discussing implementation aspects) for the sake of easy reference:

cfor: func [  ; Not this name
    "General loop based on an initial state, test, and per-loop change."
    init [block! object!] "Words & initial values as object spec (local)"
    test [block!] "Continue if condition is true"
    bump [block!] "Move to the next step in the loop"
    body [block!] "Block to evaluate each time"
    /local ret
] [
    if block? init [init: make object! init]

    test: bind/copy test init
    body: bind/copy body init
    bump: bind/copy bump init

    while test [set/any 'ret do body do bump get/any 'ret]
]

General problems with user-level control structure implementations in Rebol 3

One important general remark for all user-level implementation of control constructs in Rebol 3: there is no analogue to Rebol 2's [throw] attribute in R3 yet (see CureCode issue #539), so such user-written ("mezzanine", in Rebol lingo) control or loop functions have problems, in general.

In particular, this CFOR would incorrectly capture return and exit. To illustrate, consider the following function:

foo: function [] [
    print "before"
    cfor [i: 1] [i < 10] [++ i] [
        print i
        if i > 2 [return true]
    ]
    print "after"
    return false
]

You'd (rightly) expect the return to actually return from foo. However, if you try the above, you'll find this expectation disappointed:

>> foo
before
1
2
3
after
== false

This remark of course applies to all the user-level implementation given as answers in this thread, until bug #539 is fixed.

earl
  • 40,327
  • 6
  • 58
  • 59
3

There is an optimized Cfor by Ladislav Mecir

cfor: func [
  {General loop}
  [throw]
  init [block!]
  test [block!]
  inc [block!]
  body [block!]
] [
  use set-words init reduce [
    :do init
    :while test head insert tail copy body inc
  ]
]
sqlab
  • 6,412
  • 1
  • 14
  • 29
  • Interesting. I never thought about whether **do reduce ['print "Hello"]** would be less efficient than **do reduce [:print "Hello"]**, although I can sort of see why it *might* be. But putting function values into blocks is kind of weird. – HostileFork says dont trust SE May 17 '14 at 13:06
  • Two things to note: (1.) the above is for Rebol 2, (2.) it requires Ladislav's [set-words library function](http://www.fm.vslib.cz/~ladislav/rebol/set-words.r) to work (on current versions of R2 or R3, SET-WORDS could be replaced by the bundled COLLECT-WORDS/set). – earl May 17 '14 at 20:29
2

The other control structure that most people would use in this particular case is repeat

repeat i 10 [print i]

which results in:

>> repeat i 10 [print i]
1
2
3
4
5
6
7
8
9
10

I generally do no use loop very often, but it can be used to a similar extent:

>> i: 1 
>> loop 10 [print ++ i]
1
2
3
4
5
6
7
8
9
10

Those are some useful control structures. Not sure if you were looking for cfor but you got that answer from others.

kealist
  • 1,669
  • 12
  • 26
  • This answer gets my vote, because it points the asker to the way things are done in Rebol. The others are nice too, showing how to flexible Rebol is by creating the exact function as the asker thought it would be in his translation to Rebol. – iArnold May 17 '14 at 19:04
1

I have implemented a function that works in the same way as a C for loop.

cfor: func [init condition update action] [
    do init
    while condition [
        do action
        do update
    ]
]

Here's an example usage of this function:

cfor [i: 0] [i < 10] [i: i + 1] [
    print i
]
Anderson Green
  • 30,230
  • 67
  • 195
  • 328
  • Great minds think alike! *(I've already proposed putting the exact same thing in the box, with the same name. :-P)* Do note that you can constrain the typesets in the function specification dialect such as with **[init [block!] condition [block!] update [block!] action [block!]]** (not to mention putting in documentation strings, I assume you know of that?) FOR in its current state is considered a joke, and it should be dialected, so like **for x [1 thru 10] [print x]** ending in 10 and **for x [1 to 10] [print x]** ending in 9. That is still being designed if you have input. – HostileFork says dont trust SE May 17 '14 at 06:18
  • Quick data point since I happened across it...I now believe this should simply be called **for**, with the loop dialect taking **loop**. [Here is an implementation](https://github.com/hostilefork/rebol-proposals/blob/master/loop-dialect.reb#L151). If you haven't seen the [Ren Garden](https://youtu.be/0exDvv5WEv4?t=244) demo, it incorporates a large number of these proposals. – HostileFork says dont trust SE Apr 07 '15 at 10:36
0

For simple initial value, upper limit and step, following works:

for i 0 10 2 
    [print i] 

This is very close to C for loop.

rnso
  • 23,686
  • 25
  • 112
  • 234