Comparisons of incompatible types
Mark Wooding
mdw at distorted.org.uk
Tue Dec 7 18:59:54 EST 2010
John Nagle <nagle at animats.com> writes:
[Stepanov]
> makes the point that, for generic programs to work right, the basic
> operations must have certain well-defined semantics. Then the same
> algorithms will work right across a wide variety of objects.
>
> This is consistent with Python's "duck typing", but inconsistent with
> the current semantics of some operators.
This isn't a disaster. You should check that the arguments define the
necessary operations and obey the necessary axioms. Python is already
dynamically typed: this kind of proof-obligation is already endemic in
Python programming, so you've not lost anything significant.
> For example, "+" as concatenation makes "+" non-commutative. In other
> words,
>
> a + b
>
> is not always equal to
>
> b + a
>
> which is not good.
I think I probably agree with this. Concatenation yields a nonabelian
monoid (usually with identity); `+' is pretty much universally an
abelian group operator (exception: natural numbers, where it's used in
an abelian monoid which extends to a group in a relatively obvious way).
But then we'd need another operator symbol for concatenation.
Nonnegative integers act on strings properly, but the action doesn't
distribute over concatenation, which is also a shame. i.e.,
n*(a + b) != n*a + n*b
But it's a familiar notation, by no means peculiar to Python, and
changing it would be difficult.
> Exactly one of
>
> a > b
> a = b
> a < b
>
> is true, or an type exception must be raised.
This will get the numerical people screaming. Non-signalling NaNs are
useful, and they don't obey these axioms.
I think, more generally, that requiring a full total order (rather than
either a preorder or a partial order) is unnecessarily proscriptive.
Sorting only requires a preorder, for example, i.e., { (a, b) | a <= b
<= a } is an equivalence relation, and the preorder naturally induces a
total order on the equivalence classes. Topological sorting requires
only a partial order, and makes good use of the notation. As an
example, sets use `<=' to denote subsetness, which is well known to be a
partial order.
(I presume you weren't going to deny
a <= b iff a < b or a == b
or
a < b iff b > a
because that really would be bad.)
> The basic Boolean identities
>
> (a or b) == (b or a)
> not (a or b) == (not a) and (not b)
> not (not a) == a
>
> should all hold, or an type exception should be raised.
The first of these contradicts the axiom
x => x or _|_ == x
which is probably more useful. The last can't usefully be true since
`not' is lossy. But I think that, for all values a, b,
not (a or b) == not (b or a) == (not a) and (not b)
not (not (not a)) == not a
which is probably good enough. (The application of `not' applies a
boolean coercion, which canonifies adequately.)
-- [mdw]
More information about the Python-list
mailing list