Provide builders functions for all theories, which perform simplifications.
We use the convention that capital letter operations (apply) do not perform
any syntactic simplification and build exactly the tree corresponding to
its definition, while corresponding functions with lower case letter can
potentially return a different representation than what it is called with.
An example is the And vs and operation. The And needs a minimum of two
arguments, and will always produce a function application (and e1 e2 ...) with
the exact same element as provided. But the and constructor is more flexible
and will accept 0, 1 or more arguments, and will perform many simplifications. If
called with 0 argument, it would return true, while if called with 1 it would return
the element itself. Notice how in both case, even though you call the and constructor
you don't get an and in the resulting expression. Similarly, an and with many
arguments might simplify away true literals, or reduce the whole expression to
false if one element is false. The And apply method will always keep literals
without simplifying them away.
So why not always use simplifying methods? First, they are slightly more expensive
than the corresponding capital letter constructors, as they will inspect the
expressions and do some processing on them. Second, there are times where you might
want precise control over the syntax, and having syntax-only methods as primitive
is very useful. One main difference is that those constructors perform some semantics
transformations, while capital letter constructors are purely syntactic.
Finally note that one cannot assume anything more than semantics equivalence for the
returned term. The constructor is free to perform any sort of rewriting, so even
if you expect that calling and(true, false, x) should return false, it might still
return something like and(false, x). However, it will only return syntactically
correct term, so you would not get And(false). Usually, the above expression will
correctly get simplified to false, but the general way of thinking about these
constructors is as a best-effort simplification: it will do some relatively easy
and cheap simplification, but the exact contract does not specify the level of
simplification. This limitation is there as, in general, it is impossible to
properly specify the "correct" simplified form for a given formula.
Provide builders functions for all theories, which perform simplifications.
We use the convention that capital letter operations (apply) do not perform any syntactic simplification and build exactly the tree corresponding to its definition, while corresponding functions with lower case letter can potentially return a different representation than what it is called with.
An example is the
And
vsand
operation. TheAnd
needs a minimum of two arguments, and will always produce a function application (and e1 e2 ...) with the exact same element as provided. But theand
constructor is more flexible and will accept 0, 1 or more arguments, and will perform many simplifications. If called with 0 argument, it would returntrue
, while if called with 1 it would return the element itself. Notice how in both case, even though you call theand
constructor you don't get anand
in the resulting expression. Similarly, anand
with many arguments might simplify awaytrue
literals, or reduce the whole expression tofalse
if one element isfalse
. TheAnd
apply method will always keep literals without simplifying them away.So why not always use simplifying methods? First, they are slightly more expensive than the corresponding capital letter constructors, as they will inspect the expressions and do some processing on them. Second, there are times where you might want precise control over the syntax, and having syntax-only methods as primitive is very useful. One main difference is that those constructors perform some semantics transformations, while capital letter constructors are purely syntactic.
Finally note that one cannot assume anything more than semantics equivalence for the returned term. The constructor is free to perform any sort of rewriting, so even if you expect that calling and(true, false, x) should return false, it might still return something like and(false, x). However, it will only return syntactically correct term, so you would not get And(false). Usually, the above expression will correctly get simplified to false, but the general way of thinking about these constructors is as a best-effort simplification: it will do some relatively easy and cheap simplification, but the exact contract does not specify the level of simplification. This limitation is there as, in general, it is impossible to properly specify the "correct" simplified form for a given formula.