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?"
...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.