The gist is that all data types can be represented as programs, which have grammars, and ultimately can be converted to ASTs. The interpretation of the program is what leads to a value. I merge the ideas of state-based and operation-based CRDTs into one by enforcing an associative property, which is only possible if operations and states can both be built incrementally.
As an example, suppose we are applying a set of operations to a state: state_0; state_1 = op(state_0, arg_0); state_2 = op(state_1, arg_1) which can be represented as: op(op(state_0, arg_0), arg_1) We can think of this as collapsing on the state side, in the sense that changes are encoded in the state. We can also collapse on the operation side, in the sense that changes are encoded in the operation: op_0 = op(arg_0); op_1 = op(op_0, arg_1) which can be represented as: op(state_0, op(op(arg_0), arg_1)) I believe a CRDT that can collapse on either end will allow you to build conflict free replicated programs. Fundamentally what you are looking for is op(op(state, arg_0), arg_1) = op(state, op(arg_0, arg_1)), which is associativity.