PEP 532: Rework De Morgan's Laws section
This commit is contained in:
parent
b171bc0f79
commit
65b178826a
45
pep-0532.txt
45
pep-0532.txt
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue