COMPOSE of TUPLE! and PATH! (and toplevel GROUP!)

While working on @BlackATTR's query, I noticed code that was making paths (now tuples) out of components via TO TUPLE! COMPOSE of a BLOCK!. Like this:

to tuple! compose [obj clauses (kwd.1)]

But did you know that COMPOSE can act directly on TUPLE! and PATH! You could instead just write:

compose 'obj.clauses.(kwd.1)

It supports splices as well:

>> compose '(10 + 20)/a/b/(spread [c d e])/(reverse [g f])
== 30/a/b/c/d/e/[f g]

And if you remember that TUPLE! can be nested underneath PATH! (not vice versa) then you can COMPOSE/DEEP and handle mixed tuples and paths:

>> compose/deep '(10 + 20)/a/b.(spread [c d e])
== 30/a/b.c.d.e

Voids can vanish...so there can be fewer dots in an output tuple than in the input:

>> compose 'a.(if false [b]).c
== a.c

Empty splices will vanish as well:

>> compose 'a.(spread []).c
== a.c

You can't compose in NULLs as an important safety measure...central to the design!

>> compose 'a.(select [x 10 y 20] 'b).c
** Script Error: non-NULL value required (see MAYBE, TRY, REIFY)
** Near: [a ** (select [x 10 y 20] 'b) c]

But don't forget about MAYBE as the way to convert nulls to void when that's what you meant!

>> compose 'a.(maybe select [x 10 y 20] 'b).c
== a.c

You can also COMPOSE a GROUP!

In R3-Alpha, only BLOCK! would compose. Everything else was passed-through as-is, including GROUP!s (PAREN!s in their terminology)

r3-alpha>> compose quote (1 + (2 + 3))
== (1 + (2 + 3))

Red just doesn't allow it:

red>> compose quote (1 + (2 + 3))
*** Script Error: compose does not allow paren! for its value argument

So you'd wind up having to make BLOCK!s and then convert them:

red>> as paren! compose [1 + (2 + 3)]
== (1 + 5)

But in Ren-C, group composing works... it just leaves the top group as-is. And you also have quoted groups to make it easier!

>> compose '(1 + (2 + 3))
== (1 + 5)
2 Likes

Under the upcoming binding rules, you can't write it like this anymore... because quoted material is unbound. COMPOSE doesn't know where to look anything up.

As a first cut to get Query working, I had to do:

compose in [] 'obj.clauses.(kwd.1)

But with the new behavior of THE-XXX! types, there's another option:

compose @obj.clauses.(kwd.1)

It's a little rougher to look at than @word because the dot as a separator sort of puts the gravity to where you read the structure as [@obj clauses (kwd.1)] instead of @[obj clauses (kwd.1)]. I'm sure there's some visual cue syntax highlighting could give.

But you can use a space if you prefer, it will be slightly less efficient:

compose @ obj.clauses.(kwd.1)