Generalized Inertness with @

So this is an important thought, but it runs up against the problem that we don't have a good operator for putting @ on things...whereas with quotes, we have that operator.

I'm kind of attached to this:

>> @ block
== block

As opposed to this:

>> block: [a b c]

>> @ block
== @[a b c]

The reason I'm attached to it is because of the API, largely.

rebValue("append data", rebQ(value));
// vs...
rebValue("append data @", value);

So this was an advantage that quoted blocks had...which is that there is an operator for adding quote levels...and a word for it, too. QUOTE.

>> block: [1 + 2]

>> any quote block
== 1

>> any ^block
== 1

>> any ^ block
== 1

Several choices there. But nothing to turn [1 + 2] into @[1 + 2]

There's the option of @(block)...

>> block: [1 + 2]

>> @(block)
== @[1 + 2]

>> word: 'a

>> @(word)
== @a

This complicates the evaluator a bit, by making one of the @ types non-inert. But beyond complicating the evaluator, I rather like the idea that @ means "no evaluation" and it applies to the GROUP! form too.

Maybe the operator could be called INERT?

>> block: [1 + 2]

>> inert block
== @[1 + 2]

>> any inert block
== 1

That actually seems... fairly coherent. I guess this is a better name for "THEIFY".

Anyway, the concept would be that it would offer a twist for any function that automatically reduced its argument...like SPACED.

>> spaced @["hello" 1 + 2]
== "hello 1 + 2"

>> spaced ["hello" 1 + 2]
== "hello 3"

And UNPACK would be another instance of this.

1 Like

So the meaning of @ has come into focus somewhat interestingly as "leave that alone".

Even its usage in UPARSE has become a way of passing a block to a combinator by value without applying the block combinator rules. This makes @[xxx] able to act as a shorthand for ([xxx])...but it's up to a combinator to decide if it wants to distinguish them or not.

So What Should The @Branch Meaning Be?

The meaning I had been using previously was "don't isotopify the branch":

>> if true [null]
== ~null~  ; isotope

>> if true @[null]
; null

This doesn't seem to fit anymore. I'd proposed an alternative, which is a bit weird...but if you consider /x as being "optional x"...as in refinements...maybe not so weird:

>> if true [null]
== ~null~  ; isotope

>> if true /[null]
; null

I guess I can live with that.

If you're going to go with the "already evaluated" concept, that might lead you down the path of one of these options:

>> if true @[1 + 2]
== [1 + 2]

>> if true @[1 + 2]
== @[1 + 2]

>> if true @[1 + 2]
== 2

To explain why I'd make the last suggestion: it is along a line of thinking do @[1 + 2] would be 2...as if it had run the process of DO-ing inertly and the last value dropped out. This would just be part of a system of thinking where an @ block does what a plain block would if each evaluation step was just inert. :man_shrugging:

And before we think too hard on that, let's remember that currently quoting is permitting reasonable enough ways of saying the first two:

>> if true '[1 + 2]
== [1 + 2]

>> if true '@[1 + 2]
== @[1 + 2]

The only place you get a savings here is when @[1 + 2] => @[1 + 2] for a branch, because you type one less character without the quote mark to get that.

A Different Tactic: Mostly The Same, Just Tweaked?

I'll put forth the idea that if you have a type that some functions have a meaningful stake in treating different while others don't... it might be worthwhile to accept both and just treat them the same. This reduces the concerns of people needing to strip the marker off.

So @[...] and [...] could be treated the same when it's a branch. It's one idea. :man_shrugging:

There could be a twist: At one point I had suggested that the @(...) could be leveraged as the difference between passing a branch inertly and not:

>> either false (print "A", [print "AA" <a>]) (print "B", [print "BB" <b>])
A
B
BB
== <b>

>> either false @(print "A", [print "AA" <a>]) @(print "B", [print "BB" <b>])
B
BB
== <b>

Here the focus on inertness is "inert during the parameter gathering phase", but once that phase is over the normal behavior kicks in.

You might recall I'd previously suggested the inert behavior become the default behavior for GROUP!, and you'd use :(xxx) to insist on the evaluation... tying that in to the :param parameter convention. But :param seems to have a new destiny as the answer to REPEND-like functionality, so shifting to this concept might be a good idea.

And we could go ahead and throw in the idea of a shorthand for getting a variable with that:

>> x: 10

>> if true @x
== 10

Seems plausible...


Though if you're wondering why you wouldn't just make the branch:

>> either false [print "A", print "AA" <a>] @(print "B", [print "BB" <b>])

The concept is that it's code that generates a branch, so you're saving yourself a DO, and locating where to put that do.

The introduction of this idea points to a sort of difficult philosophical issue.

We're stuck between the desires of wanting light representations vs. the value of marking data and code distinctly.

We like writing:

any [
   x = y
   equal? z foo
] then [...]

And we like saying:

fruits: [apple banana orange]

But in the code/data distinction, we're not saying something we "know"...which is that we don't intend to be using the fruits block as code. If someone were to ask a question like ANY of it, they'd want to know if it was an array like [_ _ _] or not, vs. try to "run an apple".

Rather than make a separate function called ANY/INERT, I suggested we could determine by the datatype if it was an "especially inert block". This gives people the option of:

any inert fruits

Or the possibility of starting your declaration out as inert to begin with, to emphasize its non-code nature:

fruits: @[apple banana orange]

I think our bias would be to try and find ways to usually make the inertness/activeness the problem of the runtime, not something that people get hung up on in their source notation.

But how automatic do we want to make things? What if the product of a REDUCE came back with the marker:

>> reduce [1 + 2 10 + 20]
== @[3 30]

This would protect such blocks from being further reduced:

>> reduce @[3 30]
== @[3 30]

And it was your job to take it off if you didn't want the protection:

>> plain reduce [1 + 2 10 + 20]
== [3 30]

How inconvenient having the @ show up would be would depend heavily on how the system treated it. If APPEND and COMPOSE treated it just like any other block, it might not be so inconvenient to have it show up.

I just mention it as a brainstorm here, because I don't completely know where this new type is headed. We'll have to see.

But I imagine there will probably be a time and a place for having source-level BLOCK!s that are declared with @, with the intention that they will be passed to a routine that will act differently if it gets an @ block or a non-@ block.