I agree that the same syntax seems to refer to several different things. On one hand I welcome this simplicity (it’s way easier to remember that everything starts and ends with brackets, as opposed to Inform 7 where every different type of function has it’s own syntax - think events, type ofs, things, values that vary, rulebooks, etc), and on the other hand it can get confusing - there’s no reason why, except for convention, you couldn’t do (X is a room) (vs (room X)) or (X is empty) (vs (empty X)).
Though these conventions do indicate the type of predicate in themselves, somewhat. Perhaps a way to think about it is that every predicate is equal, and “unchangeable functional predicates” (I believe the Dialog manual refers to these as “traits”) are not so different from “dynamic predicates”, and a predicate is at once both what can be traditionally thought as a function and a boolean (with varying gradients along this line, “side effective predicates” behaving more of a function, while “unchangeable functional predicates” (traits) behaving more like a boolean. I believe
(now) (X is Y Z) is a special syntax that negates the former predicate, replacing it with a new boolean (
~(#cat is #in #bag) (#cat is #in #box)) .
There’s something similar in the fact that variables are interchangeable with objects in the syntax (e.g. you can say
(prevent [eat $Obj]) as well as
(prevent [eat #orange])), in that you’re really making a predicate for a whole class of objects. Dialog is pretty interesting in this regard (and in my opinion it makes it slightly more enjoyable, if not hard to begin thinking about).
Though perhaps you’re right that the manual should be clearer on the differences between these things and how Dialog handles them internally. It’s the least we could do to ease the onboarding process for new authors. Right now the best we can do is guess. @Ift, could you consider this?