Ladislav's BUILD Dialect (COMPOSE Alternative)

So this is an alternative to COMPOSE, that's sort of hybridized with REWORD.

As with REWORD, you can give it a list of variables (or functions) you want to use in substitution. But like COMPOSE you can put "instructions" in the template to run code or process the substitutions.

Well, okay. I don't see any reason why REWORD shouldn't work on blocks, and Ren-C can substitute splices:

>> reword:deep [x (y) [z] u v] {
      x: 1
      y: 1 + 1
      z: 1 + 2
      u: [contents of u]
      v: spread [contents of v]
  }
== [1 (2) [3] [contents of u] contents of v]

That's cool I guess. But for the uses I tend to have, I much prefer to have some indication on the template where substitutions will occur.

Also: I can't think of all that many cases where I'd have a separate list of substitutions like this (as opposed to values already in variables). Writing up that list seems like make-work when things are usually in variables already.

Although I will point out that using {FENCE!} is now slated to let you import variables and their values into an object by @name, which would give you a little more usability with this pattern:

>> x: 1
>> y: 1 + 1
; show Z being defined inline
>> u: [contents of u]
>> v: spread [contents of v]

>> reword:deep [x (y) [z] u v] {@x @y, z: 1 + 2, @u @v}
== [1 (2) [3] [contents of u] contents of v]

So maybe that would make me more likely to use it. Not sure. :man_shrugging:

I wouldn't think of there being "instructions" that REWORD executes in the data. If you have instructions you want to put in the template itself, you manage that with a separate COMPOSE step.

Anyway... if you aren't using REWORD, Ren-C's COMPOSE can still actually do this anyway. Though you have to point out what you want composed, and that's 4 words and 1 list (leaving only two lists uncomposed). 5/7 things carrying a marking.

How it can work: is that it has a trick up its sleeve: using decorations in order to work across different substitution types ($ can decorate a WORD!, a GROUP!, a BLOCK!, etc). If you COMPOSE:DEEP and use something like a Sigil or Quote to call out the places you want composition, it works quite well:

>> compose:deep:$ [$x ($y) [$z] $u $(spread v)]
== [1 (2) [3] [contents of u] contents of v]

(Note that it doesn't matter if you said $(spread v) or $[spread v] or ${spread v}... they're all equivalent, so use whichever makes sense...but GROUP! is probably the least jarring unless you have a reason to avoid GROUP! due to something particular about the rest of the code.)

If you are composing something with lots of $ in it, you have other choices:

>> compose:deep:^ [^x (^y) [^z] ^u ^(spread v) $undisturbed]
== [1 (2) [3] [contents of u] contents of v $undisturbed]

>> compose:deep:@ [@x (@y) [@z] @u @(spread v) $undisturbed]
== [1 (2) [3] [contents of u] contents of v $undisturbed]

>> compose:deep:~ [~x~ (~y~) [~z~] ~u~ ~(spread v)~ $undisturbed]
== [1 (2) [3] [contents of u] contents of v $undisturbed]

Any number of quotes is legal too, or quote-Sigil combos:

>> compose:deep:' ['x ('y) ['z] 'u '(spread v) $undisturbed]
== [1 (2) [3] [contents of u] contents of v $undisturbed]

>> compose:deep:'' [''x (''y) [''z] ''u ''(spread v) $undisturbed 'undisturbed]
== [1 (2) [3] [contents of u] contents of v $undisturbed 'undisturbed]

>> compose:deep:'$ ['$x ('$y) ['$z] '$u '$(spread v) $undisturbed 'undisturbed]
== [1 (2) [3] [contents of u] contents of v $undisturbed 'undisturbed]

So mechanically, there's always going to be a way to do it. Though this is certainly a pathological case, more suited to REWORD.

(I'll remind people that patterns are historically just lists or lists with an item in them, like compose:{} or compose:(<*>), and COMPOSE still defaults to plain old parentheses in both lists and strings. But these newfangled Sigil/Quote/Quasi things do pack a punch with their flexibility, and are starting to seem like the go-to choice for many scenarios.)

I don't really understand the point here. As I said above, the most interesting "multi-phase" concept is probably if you want to split work between REWORD and COMPOSE.

But again... for the things I have historically done, it's much clearer to my eyes if you decorate the places you're doing substitutions. This example isn't motivating for me.

Today's COMPOSE doesn't do this. But I guess... it could. Why not? What else would a standalone decoration mean, besides do an eval step inline?

>> compose:$ [$ 2 + 2]
== 4

>> compose:' [' 2 + 2]
== 4

Okay, that's an interesting idea. I like it. :+1:

With SPREAD you can splice or not, as you wish. As-is, is of course, the correct default:

>> compose:$ [$ reduce [3 * 4 5 + 6]]
== [[12 11]]

>> compose:$ [$ spread reduce [3 * 4 5 + 6]]
== [12 11]

COMPOSE uses the current binding context (not a list of substitutions like REWORD). So in the Ren-C world, you just declare things in scope and it will see them, even if the block itself is unbound material (this is why you can COMPOSE inside strings, even though they have no binding):

let x: ...
let y: ...
compose '[blah blah $x $y blah blah]  ; quoted block won't be bound

If you wanted to create or use an environment specific for the COMPOSE... e.g. some object that you don't want in your local scope for whatever reason...there could be a refinement to pass it as an argument:

compose:with '[blah blah $x $y blah blah] {x: ... y: ...}

But I'm not sure that's the right way to do it, having every such function carry a refinement like that. I've written up some about how that "context switching" might be done in a more general way.

Glad I Looked Because Of The Lone Sigil Idea

I'll add that. It's neat to be able to point out expressions you want to evaluate without using any container, as just an inline eval step mid-COMPOSE.

And I'll make a good-faith effort to try considering "would this COMPOSE be better done with REWORD", now that the seed is planted. I'll keep an open mind about it. But as evidence that I probably won't use it much: I do all my string interpolation in COMPOSE also, and don't touch REWORD for strings.

1 Like