2007-04-25 16:42:59 -04:00
|
|
|
|
PEP: 3141
|
2007-05-16 20:23:41 -04:00
|
|
|
|
Title: A Type Hierarchy for Numbers
|
2007-04-25 16:42:59 -04:00
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Jeffrey Yasskin <jyasskin@gmail.com>
|
|
|
|
|
Status: Draft
|
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 23-Apr-2007
|
2007-07-31 15:19:57 -04:00
|
|
|
|
Post-History: 25-Apr-2007, 16-May-2007, xx-Aug-2007
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
This proposal defines a hierarchy of Abstract Base Classes (ABCs) (PEP
|
|
|
|
|
3119) to represent number-like classes. It proposes a hierarchy of
|
2007-07-31 15:19:57 -04:00
|
|
|
|
``Number :> Complex :> Real :> Rational :> Integral`` where ``A :> B``
|
2007-05-16 20:23:41 -04:00
|
|
|
|
means "A is a supertype of B", and a pair of ``Exact``/``Inexact``
|
|
|
|
|
classes to capture the difference between ``floats`` and
|
|
|
|
|
``ints``. These types are significantly inspired by Scheme's numeric
|
|
|
|
|
tower [#schemetower]_.
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
|
|
|
|
Rationale
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
Functions that take numbers as arguments should be able to determine
|
|
|
|
|
the properties of those numbers, and if and when overloading based on
|
|
|
|
|
types is added to the language, should be overloadable based on the
|
2007-05-16 20:23:41 -04:00
|
|
|
|
types of the arguments. For example, slicing requires its arguments to
|
2007-07-31 15:19:57 -04:00
|
|
|
|
be ``Integrals``, and the functions in the ``math`` module require
|
2007-05-16 20:23:41 -04:00
|
|
|
|
their arguments to be ``Real``.
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
|
|
|
|
Specification
|
|
|
|
|
=============
|
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
This PEP specifies a set of Abstract Base Classes, and suggests a
|
|
|
|
|
general strategy for implementing some of the methods. It uses
|
|
|
|
|
terminology from PEP 3119, but the hierarchy is intended to be
|
|
|
|
|
meaningful for any systematic method of defining sets of classes.
|
2007-05-16 20:23:41 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Numeric Classes
|
|
|
|
|
---------------
|
|
|
|
|
|
|
|
|
|
We begin with a Number class to make it easy for people to be fuzzy
|
|
|
|
|
about what kind of number they expect. This class only helps with
|
2007-07-31 15:19:57 -04:00
|
|
|
|
overloading; it doesn't provide any operations.
|
2007-05-16 20:23:41 -04:00
|
|
|
|
|
|
|
|
|
class Number(metaclass=MetaABC): pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Some types (primarily ``float``) define "Not a Number" (NaN) values
|
|
|
|
|
that return false for any comparison, including equality with
|
2007-07-31 15:19:57 -04:00
|
|
|
|
themselves, and are maintained through operations. That is, ``nan + x
|
|
|
|
|
-> nan`` and ``nan == nan -> False`` Because this doesn't work well
|
|
|
|
|
with the Reals (which are otherwise totally ordered by ``<``), Guido
|
|
|
|
|
suggested we might put NaN in its own type. It is conceivable that
|
|
|
|
|
this can still be represented by C doubles but be included in a
|
|
|
|
|
different ABC at runtime. **Open issue:** Is this a good idea?::
|
|
|
|
|
|
|
|
|
|
class UndefinedNumber(Number):
|
2007-05-16 20:23:41 -04:00
|
|
|
|
"""Implement IEEE 754 semantics."""
|
|
|
|
|
def __lt__(self, other): return false
|
|
|
|
|
def __eq__(self, other): return false
|
|
|
|
|
...
|
|
|
|
|
def __add__(self, other): return self
|
|
|
|
|
def __radd__(self, other): return self
|
|
|
|
|
...
|
2007-07-31 15:19:57 -04:00
|
|
|
|
# Should we demand a conversion to float?
|
|
|
|
|
|
|
|
|
|
Most implementations of complex numbers will be hashable, but if you
|
|
|
|
|
need to rely on that, you'll have to check it explicitly: mutable
|
|
|
|
|
numbers are supported by this hierarchy. ::
|
|
|
|
|
|
|
|
|
|
class Complex(Number):
|
|
|
|
|
"""Complex defines the operations that work on the builtin complex type.
|
|
|
|
|
|
|
|
|
|
In short, those are: a conversion to complex, .real, .imag, +,
|
|
|
|
|
-, *, /, abs(), .conjugate, ==, and !=.
|
2007-05-16 20:23:41 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
If it is given heterogenous arguments, and doesn't have
|
|
|
|
|
special knowledge about them, it should fall back to the
|
|
|
|
|
builtin complex type as described below.
|
2007-05-16 20:23:41 -04:00
|
|
|
|
"""
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __complex__(self):
|
2007-07-31 15:19:57 -04:00
|
|
|
|
"""Return a builtin complex instance."""
|
|
|
|
|
|
|
|
|
|
@abstractmethod
|
2007-05-16 20:23:41 -04:00
|
|
|
|
@property
|
|
|
|
|
def real(self):
|
2007-07-31 15:19:57 -04:00
|
|
|
|
"""Retrieve the real component of this number, which should subclass Real."""
|
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
2007-05-16 20:23:41 -04:00
|
|
|
|
@property
|
|
|
|
|
def imag(self):
|
2007-07-31 15:19:57 -04:00
|
|
|
|
"""Retrieve the real component of this number, which should subclass Real."""
|
|
|
|
|
raise NotImplementedError
|
2007-05-16 20:23:41 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __add__(self, other):
|
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __sub__(self, other):
|
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
2007-05-16 20:23:41 -04:00
|
|
|
|
def __neg__(self):
|
2007-07-31 15:19:57 -04:00
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __mul__(self, other):
|
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __div__(self, other):
|
|
|
|
|
raise NotImplementedError
|
2007-05-16 20:23:41 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
2007-05-16 20:23:41 -04:00
|
|
|
|
def __abs__(self):
|
2007-07-31 15:19:57 -04:00
|
|
|
|
"""Returns the Real distance from 0."""
|
|
|
|
|
raise NotImplementedError
|
2007-05-16 20:23:41 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
2007-05-16 20:23:41 -04:00
|
|
|
|
def conjugate(self):
|
2007-07-31 15:19:57 -04:00
|
|
|
|
"""(x+y*i).conjugate() returns (x-y*i)."""
|
|
|
|
|
raise NotImplementedError
|
2007-05-16 20:23:41 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
def __ne__(self, other):
|
|
|
|
|
return not (self == other)
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
The ``Real`` ABC indicates that the value is on the real line, and
|
|
|
|
|
supports the operations of the ``float`` builtin. Real numbers are
|
2007-07-31 15:19:57 -04:00
|
|
|
|
totally ordered. (NaNs were handled above).::
|
|
|
|
|
|
|
|
|
|
class Real(Complex):
|
|
|
|
|
"""To Complex, Real adds the operations that work on real numbers.
|
|
|
|
|
|
|
|
|
|
In short, those are: a conversion to float, trunc(), divmod,
|
|
|
|
|
%, <, <=, >, and >=.
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
Real also provides defaults for the derived operations.
|
|
|
|
|
"""
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
@abstractmethod
|
2007-04-25 16:42:59 -04:00
|
|
|
|
def __float__(self):
|
2007-05-16 20:23:41 -04:00
|
|
|
|
"""Any Real can be converted to a native float object."""
|
2007-07-31 15:19:57 -04:00
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
|
@abstractmethod
|
2007-05-16 20:23:41 -04:00
|
|
|
|
def __trunc__(self):
|
2007-07-31 15:19:57 -04:00
|
|
|
|
"""Returns an Integral of the same sign as self whose abs is <= self's abs."""
|
|
|
|
|
raise NotImplementedError
|
2007-05-16 20:23:41 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
def __divmod__(self, other):
|
|
|
|
|
"""The pair (self // other, self % other)."""
|
|
|
|
|
return (self // other, self % other)
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __floordiv__(self, other):
|
|
|
|
|
"""The floor() of self/other."""
|
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __mod__(self, other):
|
|
|
|
|
"""."""
|
|
|
|
|
raise NotImplementedError
|
2007-05-16 20:23:41 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
2007-05-16 20:23:41 -04:00
|
|
|
|
def __lt__(self, other):
|
2007-07-31 15:19:57 -04:00
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
def __le__(self, other):
|
|
|
|
|
# Assume that if other is Real, it defines an ordering
|
|
|
|
|
# consistent with this class, or returns NotImplemented.
|
2007-05-16 20:23:41 -04:00
|
|
|
|
if isinstance(other, Real):
|
2007-07-31 15:19:57 -04:00
|
|
|
|
return not (other < self)
|
|
|
|
|
|
|
|
|
|
# Concrete implementations of Complex abstract methods.
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
def __complex__(self):
|
|
|
|
|
return complex(float(self))
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@property
|
|
|
|
|
def real(self):
|
|
|
|
|
return self
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@property
|
|
|
|
|
def imag(self):
|
|
|
|
|
return 0
|
2007-05-16 20:23:41 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
There is no built-in rational type, but it's straightforward to write,
|
2007-07-31 15:19:57 -04:00
|
|
|
|
so we provide an ABC for it. *Open issue*: Add Demo/classes/Rat.py to
|
|
|
|
|
the stdlib?::
|
2007-05-16 20:23:41 -04:00
|
|
|
|
|
|
|
|
|
class Rational(Real, Exact):
|
2007-07-31 15:19:57 -04:00
|
|
|
|
""".numerator and .denominator should be in lowest terms."""
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
@property
|
|
|
|
|
def numerator(self):
|
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
@property
|
|
|
|
|
def denominator(self):
|
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
# Concrete implementation of Real's conversion to float.
|
2007-05-16 20:23:41 -04:00
|
|
|
|
def __float__(self):
|
|
|
|
|
return self.numerator / self.denominator
|
|
|
|
|
|
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
And finally integers::
|
|
|
|
|
|
|
|
|
|
class Integral(Rational):
|
|
|
|
|
"""Integral adds a conversion to int and the bit-string operations."""
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __int__(self):
|
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
|
@abstractmethod
|
|
|
|
|
def __lshift__(self, other):
|
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __rshift__(self, other):
|
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __and__(self, other):
|
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __xor__(self, other):
|
|
|
|
|
raise NotImplementedError
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
@abstractmethod
|
|
|
|
|
def __or__(self, other):
|
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
|
|
# Concrete implementations of Rational and Real abstract methods.
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
def __float__(self):
|
|
|
|
|
return float(int(self))
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
@property
|
2007-07-31 15:19:57 -04:00
|
|
|
|
def numerator(self):
|
|
|
|
|
return self
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
@property
|
2007-07-31 15:19:57 -04:00
|
|
|
|
def denominator(self):
|
|
|
|
|
return 1
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
|
|
|
|
|
Exact vs. Inexact Classes
|
|
|
|
|
-------------------------
|
|
|
|
|
|
|
|
|
|
Floating point values may not exactly obey several of the properties
|
|
|
|
|
you would expect. For example, it is possible for ``(X + -X) + 3 ==
|
|
|
|
|
3``, but ``X + (-X + 3) == 0``. On the range of values that most
|
|
|
|
|
functions deal with this isn't a problem, but it is something to be
|
|
|
|
|
aware of.
|
|
|
|
|
|
|
|
|
|
Therefore, I define ``Exact`` and ``Inexact`` ABCs to mark whether
|
|
|
|
|
types have this problem. Every instance of ``Integral`` and
|
|
|
|
|
``Rational`` should be Exact, but ``Reals`` and ``Complexes`` may or
|
|
|
|
|
may not be. (Do we really only need one of these, and the other is
|
|
|
|
|
defined as ``not`` the first?)::
|
|
|
|
|
|
|
|
|
|
class Exact(Number): pass
|
|
|
|
|
class Inexact(Number): pass
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Notes for type implementors
|
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
|
|
Implementors should be careful to make equal numbers equal and
|
|
|
|
|
hash them to the same values. This may be subtle if there are two
|
|
|
|
|
different extensions of the real numbers. For example, a complex type
|
|
|
|
|
could reasonably implement hash() as follows::
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
def __hash__(self):
|
2007-07-31 15:19:57 -04:00
|
|
|
|
return hash(complex(self))
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
but should be careful of any values that fall outside of the built in
|
|
|
|
|
complex's range or precision.
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
Adding More Numeric ABCs
|
|
|
|
|
------------------------
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
There are, of course, more possible ABCs for numbers, and this would
|
|
|
|
|
be a poor hierarchy if it precluded the possibility of adding
|
|
|
|
|
those. You can add ``MyFoo`` between ``Complex`` and ``Real`` with::
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
class MyFoo(Complex): ...
|
|
|
|
|
MyFoo.register(Real)
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
Implementing the arithmetic operations
|
|
|
|
|
--------------------------------------
|
|
|
|
|
|
|
|
|
|
We want to implement the arithmetic operations so that mixed-mode
|
|
|
|
|
operations either call an implementation whose author knew about the
|
|
|
|
|
types of both arguments, or convert both to the nearest built in type
|
|
|
|
|
and do the operation there. For subtypes of Integral, this means that
|
|
|
|
|
__add__ and __radd__ should be defined as::
|
|
|
|
|
|
|
|
|
|
class MyIntegral(Integral):
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
def __add__(self, other):
|
|
|
|
|
if isinstance(other, MyIntegral):
|
|
|
|
|
return do_my_adding_stuff(self, other)
|
|
|
|
|
elif isinstance(other, OtherTypeIKnowAbout):
|
|
|
|
|
return do_my_other_adding_stuff(self, other)
|
|
|
|
|
else:
|
|
|
|
|
return NotImplemented
|
2007-07-31 17:14:18 -04:00
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
def __radd__(self, other):
|
|
|
|
|
if isinstance(other, MyIntegral):
|
|
|
|
|
return do_my_adding_stuff(other, self)
|
|
|
|
|
elif isinstance(other, OtherTypeIKnowAbout):
|
|
|
|
|
return do_my_other_adding_stuff(other, self)
|
|
|
|
|
elif isinstance(other, Integral):
|
|
|
|
|
return int(other) + int(self)
|
|
|
|
|
elif isinstance(other, Real):
|
|
|
|
|
return float(other) + float(self)
|
|
|
|
|
elif isinstance(other, Complex):
|
|
|
|
|
return complex(other) + complex(self)
|
|
|
|
|
else:
|
|
|
|
|
return NotImplemented
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
There are 5 different cases for a mixed-type operation on subclasses
|
|
|
|
|
of Complex. I'll refer to all of the above code that doesn't refer to
|
|
|
|
|
MyIntegral and OtherTypeIKnowAbout as "boilerplate". ``a`` will be an
|
|
|
|
|
instance of ``A``, which is a subtype of ``Complex`` (``a : A <:
|
|
|
|
|
Complex``), and ``b : B <: Complex``. I'll consider ``a + b``:
|
|
|
|
|
|
|
|
|
|
1. If A defines an __add__ which accepts b, all is well.
|
|
|
|
|
2. If A falls back to the boilerplate code, and it were to return
|
|
|
|
|
a value from __add__, we'd miss the possibility that B defines
|
|
|
|
|
a more intelligent __radd__, so the boilerplate should return
|
|
|
|
|
NotImplemented from __add__. (Or A may not implement __add__ at
|
|
|
|
|
all.)
|
|
|
|
|
3. Then B's __radd__ gets a chance. If it accepts a, all is well.
|
|
|
|
|
4. If it falls back to the boilerplate, there are no more possible
|
|
|
|
|
methods to try, so this is where the default implementation
|
|
|
|
|
should live.
|
|
|
|
|
5. If B <: A, Python tries B.__radd__ before A.__add__. This is
|
|
|
|
|
ok, because it was implemented with knowledge of A, so it can
|
|
|
|
|
handle those instances before delegating to Complex.
|
|
|
|
|
|
|
|
|
|
If ``A<:Complex`` and ``B<:Real`` without sharing any other knowledge,
|
|
|
|
|
then the appropriate shared operation is the one involving the built
|
|
|
|
|
in complex, and both __radd__s land there, so ``a+b == b+a``.
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
|
|
|
|
|
Rejected Alternatives
|
|
|
|
|
=====================
|
|
|
|
|
|
|
|
|
|
The initial version of this PEP defined an algebraic hierarchy
|
|
|
|
|
inspired by a Haskell Numeric Prelude [#numericprelude]_ including
|
|
|
|
|
MonoidUnderPlus, AdditiveGroup, Ring, and Field, and mentioned several
|
|
|
|
|
other possible algebraic types before getting to the numbers. I had
|
|
|
|
|
expected this to be useful to people using vectors and matrices, but
|
2007-07-31 15:19:57 -04:00
|
|
|
|
the NumPy community really wasn't interested, and we ran into the
|
|
|
|
|
issue that even if ``x`` is an instance of ``X <: MonoidUnderPlus``
|
|
|
|
|
and ``y`` is an instance of ``Y <: MonoidUnderPlus``, ``x + y`` may
|
|
|
|
|
still not make sense.
|
|
|
|
|
|
|
|
|
|
Then I gave the numbers a much more branching structure to include
|
|
|
|
|
things like the Gaussian Integers and Z/nZ, which could be Complex but
|
|
|
|
|
wouldn't necessarily support things like division. The community
|
|
|
|
|
decided that this was too much complication for Python, so I've now
|
|
|
|
|
scaled back the proposal to resemble the Scheme numeric tower much
|
|
|
|
|
more closely.
|
|
|
|
|
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
==========
|
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
.. [#pep3119] Introducing Abstract Base Classes
|
2007-04-25 16:42:59 -04:00
|
|
|
|
(http://www.python.org/dev/peps/pep-3119/)
|
|
|
|
|
|
2007-07-31 15:19:57 -04:00
|
|
|
|
.. [#classtree] Possible Python 3K Class Tree?, wiki page created by Bill Janssen
|
2007-04-25 16:42:59 -04:00
|
|
|
|
(http://wiki.python.org/moin/AbstractBaseClasses)
|
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
.. [#numericprelude] NumericPrelude: An experimental alternative hierarchy of numeric type classes
|
2007-04-25 16:42:59 -04:00
|
|
|
|
(http://darcs.haskell.org/numericprelude/docs/html/index.html)
|
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
.. [#schemetower] The Scheme numerical tower
|
|
|
|
|
(http://www.swiss.ai.mit.edu/ftpdir/scheme-reports/r5rs-html/r5rs_8.html#SEC50)
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
Acknowledgements
|
|
|
|
|
================
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
2007-05-16 20:23:41 -04:00
|
|
|
|
Thanks to Neil Norwitz for encouraging me to write this PEP in the
|
|
|
|
|
first place, to Travis Oliphant for pointing out that the numpy people
|
2007-07-31 15:19:57 -04:00
|
|
|
|
didn't really care about the algebraic concepts, to Alan Isaac for
|
|
|
|
|
reminding me that Scheme had already done this, and to Guido van
|
|
|
|
|
Rossum and lots of other people on the mailing list for refining the
|
|
|
|
|
concept.
|
2007-04-25 16:42:59 -04:00
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
..
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
coding: utf-8
|
|
|
|
|
End:
|