A concatenative programming language is a programming language where the inputs and outputs of functions are not explicitly specified, and instead a program is defined by chaining them together. Concatenative-like syntax is common, like in fluent object-oriented interfaces or Unix pipes, as it's a quite natural way of thinking about computation: I have a value, and I want to pass it through a sequence of elements in order.
I would argue this forms a natural model for representing the semantics of CSS selectors. But hang on -- aren't CSS selectors notoriously left-associative? I say notorious because this makes it difficult to construct certain rules. If CSS selectors don't combine in a fully associative way, then they can't be understood as function composition.
It seems to me this problem only arises because of the rather natural tendency to interpret CSS combinators like ,
>
, +
, and such as being binary operators. And indeed, you can interpret the syntax in that way, and with the rules about left associativity you get a fully self-consistent semantics.
But I think it's actually more natural to understand these operators as combining with the selector on their right to form a single unit. So instead of parsing a selector like div > p + .x
as being (div > p) + .x
and then asking why it can't parse as div > (p + .x)
, you understand it as (div) (> p) (+ .x)
. If you do this, each sectioned unit can be understood as one independent function from the power set of DOM nodes to itself.
You can understand this as being a form of unary operator, but I don't think this is the best way of thinking about it, as otherwise you'd need to add a restriction at the level of abstract syntax on why you can't apply it to a non-simple-sequence selector (> (p + .x)
).
So, if div
, > p
, and + .x
are functions, what do they operate on? They operate on sets of DOM nodes. These DOM nodes are not unbound from their originating DOM document; if you like, they are by-reference, not by-value. This must be specified, because otherwise combination of CSS selectors could result in duplication of nodes, which is out-of-spec. The initial value is the set of all DOM nodes.
This scheme offers something like a denotational semantics of what the CSS spec calls "complex selectors". It can be extended to lists of complex selectors, but in that case we leave the strict concatenative paradigm and enter the more general "function-level" paradigm, where the comma serves as something like a functional form.