I really like this trailing slash thing, meaning "get me the action as is and don't run it AND guarantee it's an action".
>> replace [a 1 a <baby>] word?/ <ice>
== [<ice> 1 <ice> <baby>]
That's to me just about perfect:
-
You're passing the parameter of what to replace as being an antiform action, so it will be called on the elements.
-
It does NOT take a parameter (notice the slash dividing it from what comes after it? that's a strong semiotic hint that
<ice>
is not a parameter toword?
) -
...and it's an antiform, so you know it doesn't occur literally in the block.
Before this form existed, I was using MATCHES which made an antiform action for a datatype:
>> replace [a 1 a <baby>] matches word! <ice>
== [<ice> 1 <ice> <baby>]
That's slower, wordier, and more opaque about the mechanics.
It's useful if you have a datatype in your hand and need to convert it to a function, or if you have a more complex type construction:
>> replace [a 1 a <baby>] matches [word! integer!] <ice>
== [<ice> <ice> <ice> <baby>]
Maybe it should be called MATCHER, since it's actually a function generator. MATCHES looks a little too much like MATCH, so it seems like it might take <ice>
as an argument.
If you make such a call often, you wouldn't want to regenerate the function each time:
>> word-or-int?: matcher [word! integer!]
>> replace [a 1 a <baby>] word-or-int?/ <ice>
== [<ice> <ice> <ice> <baby>]
MATCHES would seems like it's providing an answer in the moment, whereas MATCHER works better for when you're not using immediately. So it's probably the better choice.
Anyway, I'll also say that the REPLACE "ALL" semantic being the default is a big improvement.