PEP 532: Rework De Morgan's Laws section

This commit is contained in:
Nick Coghlan 2016-12-12 16:03:39 +10:00
parent b171bc0f79
commit 65b178826a
1 changed files with 24 additions and 21 deletions

View File

@ -778,37 +778,40 @@ combination of ``not`` operations.
For ``and`` and ``or`` in Python, these invariants can be described as follows::
assert (A and B) == (not (not A or not B))
assert (A or B) == (not (not A and not B))
assert bool(A and B) == bool(not (not A or not B))
assert bool(A or B) == bool(not (not A and not B))
That is, if you take one of the operators, invert both operands, switch to the
other operator, and then invert the overall result, you'll get the same
answer as you did from the original operator. (This may seem redundant,
but in many situations it actually lets you eliminate double negatives and find
tautologically true or false subexpressions, thus reducing the overall
expression size).
answer (in a boolean sense) as you did from the original operator. (This may
seem redundant, but in many situations it actually lets you eliminate double
negatives and find tautologically true or false subexpressions, thus reducing
the overall expression size).
For circuit breakers, defining a suitable invariant is complicated by the
fact that they're designed to eliminate themselves from the expression result
when they're short-circuited, which is an inherently asymmetric behaviour.
Accordingly, that inherent asymmetry needs to be corrected for when mapping
De Morgan's Laws to the expected behaviour of symmetric circuit breakers.
fact that they're often going to be designed to eliminate themselves from the
expression result when they're short-circuited, which is an inherently
asymmetric behaviour. Accordingly, that inherent asymmetry needs to be
accounted for when mapping De Morgan's Laws to the expected behaviour of
symmetric circuit breakers.
One way this complication can be addressed is to wrap the operand that would
otherwise short-circuit in ``operator.true``, ensuring that when ``bool`` is
applied to the overall result, it uses the same definition of truth that was
used to decide which branch to evaluate, rather than applying ``bool`` directly
to the circuit breaker's input value.
Specifically, for the new short-circuiting operators, the following properties
would be reasonably expected to hold for any well-behaved symmetric circuit
breaker that implements all of ``__bool__``, ``__not__``, ``__then__``, and
``__else__``:
breaker that implements both ``__bool__`` and ``__not__``::
cb_A = to_cb(A)
cb_B = to_cb(B)
assert (B if cb_A) is short_circuit(not (not cb_A else not cb_B))
assert (cb_A else B) is short_circuit(not (not cb_B if not cb_A))
assert bool(B if true(A)) == bool(not (true(not A) else not B))
assert bool(true(A) else B) == bool(not (not B if true(not A)))
Where ``to_cb`` returns a symmetric circuit breaker that produces the supplied
value when short-circuited, and ``short_circuit`` is defined as::
def short_circuit(expr):
return expr if expr else expr
Note the order of operations on the right hand side (applying ``true``
*after* inverting the input circuit breaker) - this ensures that an
assertion is actually being made about ``type(A).__not__``, rather than
merely being about the behaviour of ``type(true(A)).__not__``.
At the very least, ``types.CircuitBreaker`` instances would respect this
logic, allowing existing boolean expression optimisations (like double