@WORD, @SOME/PATH, @(SOME GROUP), and @[SOME BLOCK]

#1

Much of Rebol's appeal lies in its diverse collection of parts. One of the parts that has been coveted for a while is @foo.

Questions have arisen on what to call this. AT! has been suggested, though this can get a bit confused with the AT operation in the language. (TO-AT also looks kind of strange).

Other concepts have been to retake HANDLE!, call it IDENTITY! or simply merge it with EMAIL!...which is what Red has done:

>> type? @foo
== email!

>> any-string? @foo
== true

While simply seeing it as an extension of EMAIL! has come up as an option, other questions have been asked about whether it should be an ANY-WORD! and have binding. I liked the idea of it having binding, because I like it being able to be thought of as "pointing" at something. For instance, being used to implicate a parameter in a FAIL:

foo: func [bar [integer!]] [
    if bar >= 1020 [fail @bar "Must be less than 1020"]
]

But now I think that @ may be able to serve a greater purpose for us as a modifier that is like GET-XXX! and SET-XXX!, in that you can apply it to WORD!, PATH!, GROUP!, and BLOCK!. It would fulfill some of the motivation of having another ANY-WORD! type without being mixed up with the things that made ISSUE! a bad ANY-WORD! (e.g. we knew #123-45 should be an ISSUE, while :123-45 wouldn't be a valid GET-WORD!)

And it can provide an otherwise missing ability: Irreducibility.

Irreduciblity: the missing link for enumerated types

There's a problem I have pointed out that shows up when you try and use a WORD! in an enumeration.

which: pick [foo baz bar] n
do compose [
     select data (which)
     ...
]

The words look nice, but they're just one evaluative step away from being looked up as variables. You can quote things--now anything you want. But that only delays the problem...once you evaluate the apostrophe vanishes, and now you're back to the same problem again. You're always trying to compensate for how many evaluations you are doing to line up the quoting levels.

If you imagine the AT-XXX! types not evaluating, they do something you couldn't do before, unless you used an ISSUE!. But as I say, the applications of ISSUE! don't really fit with WORD!s and symbol comparisons. And # is already overtaxed in the language for so many things, that if we suddenly became prescriptive about using it for symbolic enumerations then that would be a whole lot of #'s.

This would not only soften the blow of losing bindings in ISSUE!, but it would open doors to questions like what @(...) or @[...] could mean in dialects. The @(...) could be the instruction for getting an evaluative product to KEEP that's not reused as a rule (the way :(...) would be)

>> did parse [a a a] [collect data [
    some [keep 'a keep @(reduce ["b" 1 + 2])]] end
]
== true

>> data
== [a "b" 3 a "b" 3 a "b" 3]

I was using GET-BLOCK! for that, but I think this would probably be better.

In the main evaluator, AT-BLOCK! is a bit redundant, given that blocks don't evaluate in the first place. But who knows what uses they might have. For instance following the line of thinking with PARSE, keep @[...] could be used to mean keep literally that block's contents with no evaluations.

AT-PATH! could play a pivotal part in NewPath, because plain PATH!s are too "lively", and if you compose them places they will evaluate. Quoting is not enough. You need full-on-dead, and this does it.

It looks to be ticking several design boxes for this long-desired feature. Think I'm liking it. Anyone have thoughts?

#2

I like it too. I'll be curious to see what @rgchris thinks.

1 Like
#3

Probably likes ISSUE!s coming back as ANY-STRING!, probably likes the concept, may not like the name.

AT doesn't sound very meaningful. And :foo and foo: are not COLON-WORD! and WORD-COLON! respectively. Putting AT in the name might be too much in the vein of PAREN!.

Having @foo be "SYMBOL!" or something like that would be a more appealing name, but it needs to connote its membership in its family. Needs to be short. SYM- for "symbolic"? (SYM-WORD! SYM-BLOCK!...) LINK, to be that it's pointing to something? LINK-WORD!, LINK-BLOCK!...

Weirder: DEAD-WORD!, DEAD-BLOCK! :-/

I feel kind of like maybe going long and calling them SYMBOL-WORD!, SYMBOL-BLOCK!, ... might be all right. It's not that long in the scheme of things, remember REFINEMENT? Just one more character for symbol, zero more for inert:

SYMBOL-WORD!
REFINEMENT!
INERT-WORD!

What I don't like about INERT is that it says too much about what the thing does, and that's really up to the dialect. SYMBOL-WORD! doesn't really say anything about behavior.

We should have ways to define shorthands, so if people wanted to in their own code abbreivate it they could, perhaps to just SYMBOL!. But I'd like the official name to keep it squarely in the WORD! class (or whatever class it's attached to).

For visibility, I wonder if @(...) makes more sense for PARSE rule splicing than the more slight **:(...)

parse ["a" @(either mode = <bmode> '[some "b"] '[any "c"]) "d"]

parse ["a" :(either mode = <bmode> '[some "b"] '[any "c"]) "d"]

Especially when things are broken up across multiple lines, I think the colon could be easy to overlook.

Also: since @(...) would have no meaning other than "inert group" in the evaluator, this isn't competing with an existing definition the way a GET-GROUP! would be, as being associated directly with a GET operation.

As with most such things, probably best to just make it and see what happens. Shouldn't be too hard, slight variation on code that already exists for GET-GROUP! and GET-BLOCK!

#4

Sounds good. Namingwise I like symbol-foo best so far. (or sym-...)

1 Like
#5

I just had wacky idea of sorts.

You can use '/foo to quote refinement-style PATH! and get a PATH! back. Then with this you also have @/foo if you need an inert one. (I think that I'm starting to become comfortable with the notion that PATH! isn't inert otherwise, and NewPath just has to use @/some-dir/file.txt.)

So...what if plain /foo was a way of accessing variables without running functions (like a GET-WORD!) -but- that did not tolerate unsets?

I've always felt a bit uncomfortable about the dual-nature of GET-WORD! when using it to suppress a function call, but then also getting the null and void tolerance. And when using a GET-WORD! for null or void tolerance, it's not clear that's why you're doing it. This would make it so if you ever saw a GET-WORD! you'd know that's what it's for.

You might also find it more pleasing for readability to know if something was a refinement:

 something: function [x /foo /bar] [
     if any [/foo /bar] [...]
 ]

One wouldn't have to use it that way, it would be an option. And the way I've suggested the APPLY dialect working, you wouldn't be able to pass refinements through this way (you'd have to use plain words or put them in GROUP!s or something). But that's the nature of dialecting, these parts get used for different purposes, and it's up to you to control the chaos in the way most relevant for what you are wanting to say.

ANY-WORD! and ANY-STRING!: The Limits of Unification
#6

I had another wacky half-baked fleeting thought that I thought I'd write down.

We've been looking for a way to represent datatypes symbolically. Today it's an ugly problem:

>> stuff: compose [(integer!) integer!]
== [integer! integer!]

>> type of first stuff
== datatype!

>> type of second stuff
== word!

Because we don't know what all people might want to use @ for, I haven't thought this entirely through, but what if...

>> stuff: compose [(integer!) integer!]
== [@integer integer!]

And what if it were a TYPE-WORD!

It's only a little step toward thinking of it as also being able to be an "enumerated type word", which makes its name have a bit of a double-meaning...

How does this apply to TYPE-BLOCK!, and TYPE-GROUP!, and TYPE-PATH!? Don't know, but we need some sort of notation for compound types that can't be summarized by a symbol. It could be a language: @[matrix integer [32 32]] coming back as the TYPE OF a 32x32 matrix? :-/

Just brainstorming here, I'm completely making things up. But if conflating WORD!s and enums was a thing people did before. How bad is conflating datatypes with enumerations? They'd collide sometimes, but there's only so many types...applications collide.

Does interfere with some creative uses of them, though. e.g.

 >> parse [1 1 1] [copy x some @integer]
 >> x
 == 1 1 1

PARSE would basically be surrendering creative uses. Because if copy x some integer! needs to work, and integer!: @integer, then so do literal things.

Anyway, just saying that TYPE- is a short prefix, starts with a different letter than SET- and GET-, and could maybe give a reason this inert non-reducing type exists. You could do what you wanted with it, unless it would break you by conflating with datatypes.

(Mentioning these things--even if they're bad ideas--can sometimes lead to good ones...)

Should DATATYPE! be killed off (in favor of @integer, @word, etc?)
#7

IIRC you thought about removing "." from valid word characters. I think having @ domain could be a frequent wish, e.g. @hostilefork.com .

#8

That would suggest that TUPLE! is in the class with PATH! in offering the SET-, GET-, and @ variants.

 hostilefork.com:
 :hostilefork.com
 @hostilefork.com

Just in terms of how things work it would be difficult to offer SET-, GET-, @ versions of everything. We run out of bits. It also creates a zoo of types that may do more harm than good, and ambiguities in scanning (PATH! and TUPLE! will be limited in what types they can store). But I think the similarity to PATH! as a kind of container makes it sensible to offer this, and you raise a good point that people would want such a form.

#9

At the risk of causing mass hysteria...I actually kind of like the names LIT-WORD!, LIT-BLOCK!, LIT-PATH!, and LIT-GROUP!. It's not just that I want a different letter than S (SYM/SET). But it's also that. :slight_smile:

I've laid out what the difference is between quoting and literalness. And what's being described here for these items, having them be evaluator-inert, suggests you'd never need to say lit @foo. Because it's already as literal as it can get.

The challenging bit of this would be that:

>> lit foo
== foo  ; literally the word foo...not the LIT-WORD! @foo

>> to lit-word! 'foo
== @foo  ; you'd have to do something like this

But then again, we don't expect set foo to give back foo:, that's not what the operator does.

#10

I'm admittedly partial to the 'HANDLE!' usage of @, so I'd mourn that as a loss. My initial superficial reaction is a little queasiness at an additional symbol kicking around and adding that cognitive load, but I would need to think about what it adds to the language and where it'd produce some wins before settling on that as a judgement.

#11

It's not clear what this is in reference to...you mean you are partial to the name HANDLE! ?

My initial superficial reaction is a little queasiness at an additional symbol kicking around and adding that cognitive load

I'd be more worried if it weren't providing a clear mechanical purpose.

Having them be LIT-WORD!, LIT-PATH!, LIT-GROUP!, LIT-BLOCK! feels right. We're still keeping the type load about the same, with one QUOTED! datatype as a kind of "container". All in all I think the load is actually going down.

#12

Not the name 'HANDLE!' for sure, just the notation primarily referencing the @123abc user name convention.

#13

If then you mean it not being an ANY-STRING! thus limiting the range of legal names to valid formations of ANY-WORD!...you'd have some workarounds e.g. @["123abc"]

This points the way toward saying that to text! @["123abc"] needs to be 123abc, perhaps FORM-ing as @123abc I think we can push the shape around a bit to make this stuff easier for real-world scenarios.

#14

After looking at this a while, I think my heart is set on LIT-WORD!, LIT-PATH!, LIT-GROUP!, and LIT-BLOCK!... even with the confusion it might cause for historical code.

The GET/SET/LIT has a good rhythm to it and helps explain the behavior of the type in the default evaluator.

I like the spread across letters (no SET/SYM)...and that each is a related operation in its own right in the language (LIT is a basic function, SYM is not).

So this is where I'm leaning toward right now...