APPLY II: The Revenge!

I'd said "It's time to bring back APPLY".

...and by "it's time" I apparently meant "within the next year, maybe?"...

But better late than never, right? It's in!

Refinements Can be Provided In Any Order

[a b c d e d e] = apply :append [[a b c] [d e] /dup 2]
[a b c d e d e] = apply :append [/dup 2 [a b c] [d e]]
[a b c d e d e] = apply :append [[a b c] /dup 2 [d e]]

[a b c d d] = apply :append [/dup 2 [a b c] [d e] /part 1]
[a b c d d] = apply :append [[a b c] [d e] /part 1 /dup 2]

Any Parameter (Not Just Refinements) Can Be Used By Name

Once a parameter has been supplied by name, it is no longer considered for consuming positionally.

[a b c d e] = apply :append [/series [a b c] /value [d e]]
[a b c d e] = apply :append [/value [d e] /series [a b c]]

[a b c d e] = apply :append [/series [a b c] [d e]]
[a b c d e] = apply :append [/value [d e] [a b c]]

Commas Are Ok So Long As They Are Interstitial

[a b c d e d e] = apply :append [[a b c], [d e], /dup 2]
[a b c d e d e] = apply :append [/dup 2, [a b c] [d e]]

>> apply :append [/dup, 2 [a b c] [d e]]
** Script Error: end was reached while trying to set /dup

Giving Too Many Arguments Defaults To An Error

>> apply :append [[a b c] [d e] [f g]]
** Script Error: Too many values in processed argument block of APPLY.

If you want, you can ask it to /RELAX

>> apply/relax :append [[a b c] [d e] [f g]]
== [a b c [d e]] 

Refinements Must Be Followed By A Non-Refinement

>> apply :append [/dup /part 1 [a b c] [d e]]
** Script Error: end was reached while trying to set /dup

But you can pass refinements as arguments to refinements...just use a quote!

>> tester: func [/refine [any-value!]] [refine]

>> apply :tester [/refine '/ta-da!]
== /ta-da!

No-Arg Refinements Permit OKAY and NULL

Remember: the EVAL FRAME! mechanics do not change anything. So if a refinement doesn't take an argument, the only legal values for that refinement in the frame are OKAY and NULL.

>> testme: func [/refine] [refine]

>> apply :testme [/refine okay]
== ~okay~  ; anti

>> apply :testme [/refine null]
== ~null~  ; anti

>> apply :testme [/refine 1020]
** Error: No-Arg refinements can only be ~okay~ and ~null~ antiforms

^META Arguments Are Accounted For

APPLY detects when a parameter is meta and will level it up...because the low-level frame mechanics aren't allowed to editorialize:

>> non-detector: func [arg] [arg]  ; not a meta argument, isotopes illegal

>> apply :non-detector [pack [10 20]]
== 10

>> detector: func [^arg] [arg]

>> apply :detector [pack [10 20]]
== ~['10 '20]~

I know not everyone has gotten their heads around isotopes yet, but they are critical... this stuff was the missing link to making it all gel.

:dizzy: :dizzy: :dizzy:

2 Likes

6 posts were split to a new topic: Naming The Infix APPLY Operator

A post was split to a new topic: Critiquing Red's Updated APPLY Implementation

And now APPLY has an infix shorthand...

Meet The // Operator!

The choice to use slashes for the operator became obvious, now that /WORD Runs Functions (and :WORD is taking over refinement!)

>> append // [[a b c] <d> :dup 2]
== [a b c <d> <d>]

>> append // [:dup 2 [a b c] spread [e f]]
== [a b c e f e f]

>> append:dup // [[a b c] [e f] 2]
== [a b c [e f] [e f]]

It's strange but also it's a mixture of heavy and light, as a kind of "joiner" or concatenator, almost as if you were sticking the things together into a single thought.

append//[[a b c] <d> :dup 2]

I know it's not perfect, but nothing will be. I don't like an APPLY operator that sits to the left and quotes:

apply append [[a b c] <d> :dup 2]  ; !!! bad

Because that makes it look too much like the BLOCK! is the first argument to APPEND. So you really have to do APPLY with an inert form:

apply get $append [[a b c] <d> :dup 2]

apply append. [[a b c] <d> :dup 2]

So if no GET-WORD! is to be used and quoting is in play, there has to be something learnable and infix to jolt the flow. I've tried a lot of things at this point, this feels like the logical conclusion.

append // [[a b c] <d> :dup 2]
1 Like