On formal symmetry-breaking in Roam Research - and one proposed way to do it
intended audience: hardcore Roamophiles
Hi guys!
This short essay has a rather specific audience - namely, my fellow RoamResearch early adopters who have been pushing the envelope for ~12 months figuring out what we can and cannot do, on the platform.
I’m writing it to describe a fairly specific problem in Roam’s semantic annotation capability - namely, that it currently seems to lack a symmetry-breaking operation - and, I will also propose a solution. Two solutions, to be exact - though one is better than the other, in my opinion. (Feel free to kindly let me know, if you have a better solution for this problem.)
The problem is that there are some kinds of relationships that I want to annotate, and the relationships are very specifically one-way relationships, with an arrow (of time, causality, or dependence of some kind)
For example, what if [[Sammy]] [[owes money to]] [[Johnny]].
I’d like to be able to perform various different kinds of operations on information like this; for example, to find all the people Sammy owes money to, but perhaps I’d like to find all the people who owe Johnny money, or who owe Sammy money, or who Johnny owes money to. All query-directions might be important, in different cases.
As is, currently, the [[query]] function treats all the information in a tree of nodes leading from a parent to a node as if it a were a single, flattened, unordered set. Therefore I can do a search for either [[owes money to]] [[Johnny]] or [[owes money to]] [[Sammy]], and Roam will register the exact same result, either way, when it encounters [[Sammy]] [[owes money to]] [[Johnny]]. It doesn’t discriminate along any ordered axis, amongst the tags.
This is also true, no matter where either entity is nested relative to another. Although nesting provides a clear visual asymmetry, it does not constitute a formal distinction within the language of querying. There is, essentially, no existing way to “break symmetry” and annotate a one-way relationship of any kind that will make a difference within the language of a {{query:}} as it currently exists.
(… of course, you can just use natural language to annotate it, but I am specifically interested in extending the power of the formal language to include this. For some use cases, I need a powerful and generalizable formal tool.)
“But WAIT! You promised me a solution”, you say!
There are at least two solutions. You can make up your mind, but I think the second one is more powerful and generalizable.
The first solution that occurs to me that the asymmetry can indeed be coded if you literally change the name of the link, for the sender vs receiver. You can use, for example, [[—>Johnny]]. This is kind of the hack that lots of multiplayer Roam users are now using when they want someone’s attention - [[@Frankie]], for example, might be constituted to just mean, “Frankie, check this out!”.
[[Sammy]] [[owes money]] [[—>Johnny]] would be a solution of this kind. I just created a new page title, and I can use it to differentiate the meaning of the sentence.
But that’s a little bit cumbersome, to be honest. It requires multiplying page names, and by the time I’ve created instances for all such possibilities and all such contexts, I might not be sure how to get to any of them when I need them.
I have a better idea. What if we use “nested blocks” - specifically, how about using a link like [[➡️]] - but compounded , i.e. nested, within a new page-link, with the proper name, to mean “to that person”. My new statement is now:
[[Sammy]]
[[owes money]] [[ [[➡️]] [[Johnny]] ]]
Note that I have created a new page called [[ [[➡️]] [[Johnny]] ]] to denote directionality. You’ll also note that this new page is a complex, or “nested”, page title.
This allows me to formally differentiate between Johnny-as-subject and Johnny-as-object, but without the need for creating new tags. It all remains neatly and tidily arranged around a few simple tags, including the new, symmetry-breaking tag [[➡️]], which now serves its own purpose, within the database.
I’ve now broken the symmetry.
Now, take the above example.
If I want to search for all the people whom Sammy-as-subject owes money to, I just search for [[Sammy]] and [[owes money]], as I did before.
For Johnny, it’s a little trickier, but hopefully not too tricky - I search for [[Johnny]] [[owes money]] … so far so good, right? Except now I have a trick up my sleeve - I just use {not:} to exclude, from that, all the instances of Johnny-as-object. Like this
{and: {not: [[ [[➡️]] [[Johnny]] ]]} }
But if you exclude every instance in which [[Johnny]] was the identified object, then all that’s left will be all the statements, in which Johnny was the subject. Problem solved! Now I can find all sentences about whom Johnny owes money TO, and NOT the statements in which he is owed money by others.
In a slightly indirect way, I have figured out how to give instructions to the query in a way that recognizes which name came first - but this is the important part - it will generalize to any other kind of semantic ordering.
(Note that I had to achieve that, by changing my set of possible hashtags to include a new, complex hashtag - one in which the direction of asymmetry was already encoded. The hashtag itself is “doing the semantic work.”)
Of course, the real point here is that I think this can be generalized to other use-cases where asymmetry is needed.
For instance, sometimes we need to denote that [[A]] happened [[before]] [[B]] - especially if we are documenting changes in a system while we are in search of causality.
Right now, this is easy to do in natural language within Roam… but NOT easy to do within its existing formal structure. But perhaps approaches like the above will lead to further kinds of more general powers, in the formal language of Roam.
Please let me know what you discover, in your own experiments!
Looking forward to the results of more explorations.
Clever solution!
I'm not an expert, but there are features of a graph database in which Roam is based that haven't been implemented. One of these is the capacity to add properties or labels to the links (edges, in graph database terms). I guess it's going to be implemented in the near future. This is going to add extra power to Roam.
«The edges representing the relationships have two qualities: they always have a start node and an end node, and are directed; making the graph a directed graph. Relationships can also have properties. This is useful in providing additional metadata and semantics to relationships of the nodes.» https://en.wikipedia.org/wiki/Graph_database
(Similar tools like Tinderbox or Storyspace by Eastgate have had this feature for long.)
Thanks for sharing!
This is excellent, Matt. An easily implemented solution to the directionality problem.