No-Interstitial-Delimiter Sequence Proposal ("FUSED!")

@BlackATTR feels that being able to write code as operation(arg) with no space is critical to the SQL dialect. While we haven't expressly prohibited that yet, it is lossy:

>> [operation(arg)]
== [operation (arg)]

I just noticed another case of tight syntax with a %rebol-dom.r script where @Danny is trying to write expressions like:

app[.width] = "curly quew"

Also still legal at the moment, but also still broken apart...and being two separate elements means it couldn't be quoted as a unit on the left (e.g. by an assignment-oriented equal):

>> app[.width] = "curly quew"
== [app [.width] = "curly quew"]

One of the reasons we'd discussed making these kinds of constructs illegal would be to free them for new meanings.

Given that people want more density, might we think of this as a new datatype... like a PATH! or a TUPLE!, that simply has no delimiter?

Let's Imagine we call it FUSED!

>> p: operation(arg)  ; 'operation(arg) if eval active, but likely should not be
== operation(arg)

>> type of p
== ~{fused!}~  ; antiform

>> first p
== operation  ; a WORD!

>> second p
== (arg)  ; a GROUP! with one element

Plan -4 Issues

There's a bit of a problem in that we've been saying you could write (a)(b) and [a][b] and have it mean the same thing as (a) (b) and [a] [b]. I use this frequently, because I do not like the spacing gap you get when braces follow each other.

f: func [
    some-arg [integer!]
] [
    the gap there bothers me
]

f: func [
    some-arg [integer!]
][
    without the gap looks better
]

That would suggest the rules for fusing would disallow adjacent GROUP!s and BLOCK!s, which would rule out interesting fuseds that might represent multidimensional array access:

>> [foo[x][y]]
== [foo[x] [y]]  ; would have to be a fused and a block?

Ladislav was always rather adamant that spaces should be everywhere because spaces had significance. So he wasn't in favor of the aesthetic gap-closing. If FUSED! turned out to be truly useful, then it might vindicate his belief. I dunno.

How Would It Reconcile Priority With TUPLE! and PATH! ?

The interstitial delimiters prioritize by "heft" (/ is on top of : is on top of .) And you can't get much less hefty than nothing. So fuseds would be on the bottom of the totem pole.

a.b/c.d[e f] => to path! compose/deep [a.b c.(to fused! [d [e f]])]
a.b[c d]e/f => to path! compose/deep [a.(to fused! [b [c d] e]) f]

Not that these examples are very useful, but I believe that's what they should be.

There'd Be Some Issues With Numbers

If numbers are allowed, you are going to run into trouble with things like how 1e... leads into exponential notation, and the fact that you get problematic reversals with 1a and a1. The first seems like a candidate for being a FUSED!, while the second is what we'd see as a normal WORD!

No Fusing With SPACE-Terminated Paths or Tuples

You couldn't merge a/ and [b] to get a FUSED!, because a/[b] is a PATH!. (This is a natural consequence/feature and not a flaw.)

Also, while # is a legal RUNE!, it's also a modifier. So the #[a] probably shouldn't be a FUSED!. Unless there's some way that would fit into a broader master plan, by virtue of what that fused would mean...

Anyway, a lot to think about. But if people are dug in and insistent that they have to have these notations, then we should give consideration to the idea.

3 Likes

I appreciate the consideration here. I also have no idea if a FUSED! might be useful outside of a specific kind of dialect. Which I suppose isn't a very strong vote in favor.

It would be a slight boost to supporting an SQL syntax (or spreadsheet macro). My main challenge is not parsing the pattern (be it FUSED! or just word! + group!), but recursively unraveling the nested construct to translate into ren-c text! manipulating expressions.

I have a low-key need to be able to express FUSED!-like structures as though they're blocks:

foo(bar(baz)))
foo(bar, baz("bip"))
foo(bar, baz("bim", "bap"))

My CSS brain does appreciate the possibilities here—it could be a way to express small dialected values:

red: rgb(255 0 0)
move: translate(-1x1)

Or indeed SQL, or Javascript, or other things.

My Rebol brain says, this is un-Rebol-like! I certainly don't think it should become an operative Rebol language construct.

I'd be more inclined to recognizing thing( ... ) as a distinct container type recognizing the pattern across other data formats/languages. It could be inert in and of itself thus really only useful in dialects. Forgoing Plan -4 by packing certain combinations of types may tie hands with new forms in the future.

2 Likes

I do not see any particular reason why thing(...) would be more or less legitimate to want than thing[...]

And I think that if people had syntax open to thing(...)(...) and thing[...][...] they would find uses for those too.

Note the API would be the same thing as PATH! and TUPLE!: where since you have constraints on what you can form this way, and they "change types" when things are removed, they are immutable while in the fused form.

So things like this need to be illegal:

>> p: a(b)
== a(b)

>> take p
== (b)  ; looks like a GROUP!

>> take p
==  ; back to those same flaky vanishing issues

It seems to me in line with Rebolism to say these are all different:

(a)(b c)(c)
(a) (b c) (d)

a+bc+d
a + bc + d

a(b c)d
a (b c) d

a[b c](d)
a [b c] (d)

Being able to write:

>> num: 10

>> size: compose '(num)px
== 10px

...seems like a gateway to some fairly powerful things expression-wise, and I think this leads pretty quickly to wanting to do things like:

>> [num units]: parse size [pack [integer! ['px | 'em]]]
== 10

>> num
== 10

>> units
== px

But the point is that if we can lean on a general mechanic--especially one that's mostly already written--this might be a breakthrough worth a bit of shakeup... like having to put spaces between your blocks ordinarily.

2 Likes

I'd say primarily based on its history in functional notation.

I'm not much in favour of this proposal, but you got me with 10px or 11USD or 5.05EUR .
This could be really nice in a lot of dialects.

2 Likes

I still had a little bit of crack laying around from the other night, and after smoking a little of it, I started wondering...

What if WORD!s did not allow numbers?

And instead, we allowed you to make CHAINs with FUSEDs.

4chan: https://www.4chan.org

A fused with just WORD!s and INTEGER!s in it could be deemed legal for binding. Bearing in mind also that if you have variations of a function, you could do that with some-function:1 and some-function:2 dispatching to the same function but offering it the chain for processing.

:thinking:

2 posts were merged into an existing topic: Backtick Literals (and an Axis of Extensibility?)

Those are pretty good examples of why FUSED! should almost always be evaluator-inert.

So I guess we can assume things like array[n] would do nothing, and only mean "pick out of array" in some dialected application.

With backtick literals, 1x1 would be FUSED!, and `1x1` could be a PAIR!. But in dialected contexts you could transform between them.

Although hmm... if you want a function to be called convert-to-utf8 and that was a FUSED! naming it, it would have to be evaluator active. :frowning: So I guess the usual exemption for languages, where if the run is all words and integers, and starts with a word, it's active...otherwise 1x1 and 1em would be evaluator active.

1 Like

A post was split to a new topic: Dimensional Analysis with FUSED!

In a GitHub Issue @IngoHohmann asked about spacing with COMMA!, e.g. should we permit:

>> a: 20,b: "def"
** PANIC: invalid "comma" -- ",b"

>> a: 20 ,b: "def"
** PANIC: invalid "comma" -- ",b"

I doubt it should be legal, but if it were legal... the legal cases would probably have to be FUSED!... if fused was ever made:

 >> join fused! ['a ', 'b]
 == a,b

You wouldn't be able to have COMMA at the tail of a sequence, though.

I'm Starting To Think I'd Be A Fool Not To Add FUSED!

Ren-C has become profoundly rich and flexible, in ways that are mind-bending. And if you think about what FUSED! could do, it would take this further.

I'm not a huge fan of being forced into space significance for BLOCK!, e.g. [a][b] being different from [a] [b] ... and this has been a big sticking point. I've mentioned my reasoning is because I like to write my code like:

either condition [
    code
][
    other code
]

And I don't like it as much with a space between the brackets:

either condition [
    code
] [
    other code
]

Though something I have noticed with new statics via BIND is that I do not like gluing FENCE! onto block:

func [
    spec
] bind {
    var (value)
}[
    body
]

That bothers me for some reason, and I prefer a space:

func [
    spec
] bind {
    var (value)
} [
    body
]

I think that the nature of FUSED! suggests that it should PANIC by default, especially to help catch stray cases where you've made one on accident, and you usually have to quote it or use it in a dialected context.

Using RebindableSyntax you could on a case-by-case endorse some literals under evaluation for your particular domain, maybe?

I'll point out you'd now have more variations, like $10px and ^10px and @10px at your disposal for any FUSED!.

GROUP!s in Type Specs would have to mean FUSED!

If you think about matching things like @word! or 'tuple! or word!: in type specs, you see that interstitials like : have to be matched in the pattern.

>> match [word!:integer!] 'foo:10
== foo:10

>> match [word!:integer!] 'foo:<tag>
== \~null~\  ; antiform

But you can't do that for FUSED!...

>> match [integer!word!] '10px
** PANIC: integer!word! is undefined

Seems to me that this would have to steal GROUP! (or FENCE!, but GROUP! looks nicer I think).

>> match [(integer!)(word!)] '10px
== 10px

I Feel Like I'm Going To Have To Try It

The issues aren't trivial, but the dialecting potentials are enormous.

(I'll point out that @Ladislav always hated Plan -4, and thought you should have to write [a] [b] instead of [a][b], so at least one person feels the space significance is natural to respect...maybe I'd get used to it if I made myself do it.)

1 Like

If FUSED! pans out you will have cracked this thing wide open. Not only for internal dialects, but mini-languages.

If we can elegantly work with CSS and JS as @rgchris mentioned, Ren-C will have an audience of developers using it. Maybe not the kinds of elite devs you might want, but you’ll have people using this language IRL.

Working in that space of markup, JS and DOM is total drudgery. A sane language that can carve that up like a Japanese steakhouse chef would be extremely attractive for non cultists just trying to get shit done with less back and forth than an AI prompt.


And I need these for Query. I have a few things that I need sigils/decorations for.

Eventually I need to recursively unwind nested fn expressions. But that will be a second or third dev phase. Best to avoid Greenspuns tenth for now.

Select lower(trim(#field)) From <source>

Your use case is certainly one of the ones that couldn't be easily dismissed.

But the more I've considered it, the more I feel it can't be unseen... A Rebol with FUSED! will be far ahead in usefulness beyond any Rebols without it. The dialecting powers are just too great to ignore.

In non-dialected cases... I think making FUSED! error by default and not trying to imbue it with any "non-Rebolish" behaviors, but then having people take control of their specific scenarios via RebindableSyntax makes the most sense.

This way we aren't hinging any fundamental behaviors on it... like saying block[n] is a 0-based pick whereas block.(n) is a 1-based pick (just to pick a random example).

However, if you faced a circumstance where that would be useful--or wanted to do things like what @Danny is trying with the DOM language--you could, and mix it freely with other code.

So I've Committed To Trying This

It has been one of the great unknowns of the design, and we've reached critical mass I think to where it's time to bite the bullet... space out our brackets... and see where this goes.

I'm going to put on my FUSED! hat and see what I can cook up.

1 Like