Dialecting Function Calls: New, Weird, Powerful

I've not been able to get dialected function calls off my brain, and the examples just keep coming to me:

>> compose:{} "some stuff {1 + 2}, (not composed)"
== "some stuff 3, (not composed)"

>> compose:[] "some stuff [1 + 2], (not composed)"
== "some stuff 3, (not composed)"

>> compose:((*)) "some stuff ((* 1 + 2)) (not composed) ((nor this))"
== "some stuff 3, (not composed) ((nor this))"

>> foo: 10

>> compose:$ [$foo foo $(1 + 2)]
== [10 foo 3]

>> compose:' ['foo foo '(1 + 2)]
== [10 foo 3]

What about rounding?

>> numerator: 10, denominator: 3

>> numerator / denominator
== 3.3333333333333335

>> round:0.1 numerator / denominator
== 3.3

; compare with `round:to numerator / denominator 0.1`

So I've been paring away the barriers (e.g. dropping GROUP! evaluations to calculate refinements...)

How Does GET Make an ACTION! From Such a Chain?

Well firstly, I'll mention that GET making an ACTION! out of a non-dialected CHAIN! has been broken for a bit. I've called this "Refinement Promotion", and there's no shortage of headaches historically.

But really this is just another way of asking: how do you MAKE FRAME! from such a Chain?

Well, let's say you do something like:

test: func [
    arg [integer!]
    :refine [tag!]
    <chain> chain
][
    probe arg
    probe refine
    probe chain
]

The idea here is you've said you're the kind of function that wants to know something about how you were invoked with a chain. Hence perhaps:

>> test 10
10
~null~  ; antiform (refine)
~null~  ; antiform (chain)

>> test:refine 10 <twenty>
10
<twenty>
test:refine

>> test:refine:(*) 10 <twenty>
10
<twenty>
test:refine:(*)

I'm assuming a few things here:

  • It's more useful to know when you weren't invoked with a chain and test it easily than when you were invoked with a word

    • Possibly false? Should it be more about wanting to know how you were invoked... so a WORD! if a CHAIN! was not used?

    • Should for-each 'item 'word [...] be willing to decay to enumerate a word as a single element? :face_with_diagonal_mouth:

  • WORD!s were treated "as is" in terms of refinement calculations, and still appear in the chain parameter

    • Should this have worked equally well if you said test:(*):refine, effectively saying words are basically reserved in function call dialects, and so you have to use other parts of speech?

    • Or should dialected function calls begin at the first non-WORD!, with no refinement processing after that point?

Or Should Dialected function Calls Get a Narrowed BLOCK!

>> test:refine 10 <twenty>
10
<twenty>
test:refine
~null~  ; antiform ("chain")

>> test:refine:(*) 10 <twenty>
10
<twenty>
[(*)]

>> test:refine:(*):etc 10 <twenty>
10
<twenty>
[(*) etc]

This makes more sense in an APPLY scenario:

apply test/ [10 refine: <twenty> chain: [(*) etc]]

So... "You Get The First Non-WORD! and Everything After" ?

Maybe that works. This does rule out:

>> any:even? [1 3 8 7 10]
== 8

But not:

>> any:@even? [1 3 8 7 10]

>> any:$even? [1 3 8 7 10]

>> any:^even? [1 3 8 7 10]

>> any:{even?} [1 3 8 7 10]

>> any:(even?) [1 3 8 7 10]

>> any:[even?] [1 3 8 7 10]

Anyway, with some of what I've been talking about with positional refinement there's:

>> any:predicate even?/ [1 3 8 7 10]
== 8

>> any:with even?/ [1 3 8 7 10]  ; or a shorter name
== 8

So if you can move the predicate before the data maybe that's enough, vs. starting a weird pattern that might be hard to generalize... saving dialected function calls for the rare cases where they really would help.

But losing the ability to take over and use WORD!s may limit interesting cases. :man_shrugging: