[REPEAT 1] => ATTEMPT (Not As Useless As It Looks)

Historical Rebol had a use for ATTEMPT that we don't really need anymore... due to how definitional ERROR!s work and being covered by other things.

When the word was freed up, I thought This looks like a perfect name for "loop once"

I imagine you're thinking: "Why would we waste a name on loop once?" :confused:

...Hear Me Out...

I'll start by saying loop once does come up, when you're writing something that wants to expose a looping interface, but not delegating to any wrapped loops to do it.

Let's say you're trying to do this:

>> for-all-foos 'x [blah blah foo 10 blah blah foo 20] [print [x]]
10
20

(Assume you don't know about reusing FOR-EACH with a GENERATOR. Instead you decide you really do want to get into your own binding, or customization of the body, or whatever your reasoning is.)

You try driving this with PARSE

for-all-foos: lambda [var data body] [
    body: bind (var: let (var)) body  ; !!! need better way to say this
    parse data [
        opt some [
            'foo set (var) integer! (eval body)
            | elide one
        ]
    ]
]

That seems pretty good...besides me not having a great way of binding an indirect variable to a body, yet being able to still assign that variable afterwards. (Note that whatever you use for that needs to know the difference between @x to reuse a binding and x to not, e.g. it has to be a construct with the smarts of something like LET.)

But what about BREAK, CONTINUE, etc?

You need to bind body to THROW-TO-LOOP, and you have to handle that.

So REPEAT 1 might come to mind. But what about just ATTEMPT?

for-all-foos: func [var data body] [
    body: bind (var: let (var)) body  ; !!! need better way to say this
    return parse data [
        opt some [
            'foo set (var) integer! (attempt body else [return null])
            | elide one
        ]
    ]
]

So now you have your BREAK, your CONTINUE, your AGAIN, all working.

But ATTEMPT Is A Genuinely Useful Control Construct

Especially with AGAIN.

xxx: attempt [
    blah blah
    if blah blah [break]
    if blah blah [again]
    if blah blah [continue]
    blah blah
] then [
    ; code that runs if reaches end normally, or CONTINUE
] else [
   ; code that runs if BREAK
]

It's lightweight and flexible, and in general a lot clearer than INSIST (Redbol UNTIL)

Even in the most minimal circumstances, I think it's clearer:

append data insist [request-server-token else [wait 5]]

append data attempt [request-server-token else [wait 5, again]]

But it's much more powerful.