[Edu-sig] foundations,
Kirby Urner
pdx4d@teleport.com
Tue, 29 May 2001 08:37:38 -0700
I'm glad to know there's a module system of such sophistication.
Also, whereas the chapter I was citing introduces the rational
number by means of numerous Scheme procedures, it wouldn't make
a lot of sense to go to all this trouble in PLT Scheme, where
the fraction type is built in, e.g.:
> (define a (/ 3 4))
> a
3/4
> (define b (/ 1 12))
> (+ a b )
5/6
> (- a b)
2/3
> (* a b)
1/16
> (/ a b)
9
In Python, I'd do the same re modules: store the Fraction class
in a module, then import. I happen to have one handy:
>>> from mathobjects import Fraction
modules bear some resemblance to classes in that both use the
dictionary structure to define a table of contents. You can get
at the keys to a class with dir:
>>> dir(Fraction)
['__abs__', '__add__', '__div__', '__doc__', '__eq__', '__float__',
'__gt__',
'__init__', '__lt__', '__module__', '__mul__', '__neg__', '__pow__',
'__radd__',
'__rdiv__', '__repr__', '__rmul__', '__sub__', 'denom', 'fformat',
'float', 'list',
'mkfract', 'numer', 'recip', 'simplify']
Same with a module:
>>> import mathobjects
>>> dir(mathobjects)
['Fraction', 'Matrix', 'Poly', 'Sqmatrix', '__builtins__', '__doc__',
'__file__', '__name__', '__path__', 'deriv', 'polynomial', 'pyfraction',
'simplematrix']
Then use the Fraction class to instantiate objects, a and b. Because
the primitive operators have been overridden, your fraction objects
behave as expected:
>>> a = Fraction(3,4)
>>> b = Fraction(1,12)
>>> a+b
(5/6.)
>>> a-b
(2/3.)
>>> a*b
(1/16.)
>>> a/b
9
It was my decision, in the __repr__ method, to have that little decimal
point in the denominator. This allows conversion to float simply by
evaluating a stringified representation:
>>> eval(str(a+b))
0.83333333333333337
although __float__ is also defined:
>>> float(a+b)
0.83333333333333337
Using a parallel infrastructure, we would define polyhedra as another
kind of object, based on a list of coefficients as parameters:
>>> from mathobjects import Poly
>>> p = Poly([1,2,3,4])
>>> p
x**3 + 2*x**2 + 3*x + 4
>>> q = Poly([3,-2,-1,-1])
>>> p*q
3*x**6 + 4*x**5 + 4*x**4 + 3*x**3 - 13*x**2 - 7*x - 4
>>> p-q
-2*x**3 + 4*x**2 + 4*x + 5
>>> p+q
4*x**3 + 2*x + 3
A fully generalized system would allow me to use polynomials
in the numerator and denominator of Fractions, but so far my
polynomial objects don't understand the / operator --
dividing polys is somewhat difficult, especially if you plan
to simplify them (which involves finding common factors, i.e.
the gcd).
However, I *am* able to use the Fraction objects as coefficients
if I like:
>>> r = Poly([a,b,1])
>>> r
(3/4.)*x**2 + (1/12.)*x + 1
>>> r*p
(3/4.)*x**5 + (19/12.)*x**4 + (41/12.)*x**3 + (21/4.)*x**2 + (10/3.)*x + 4
And to pass values to the polynomial, as a function:
>>> s = r*p
>>> s(10)
(284437/3.)
>>> s(-12)
-158976
Note that s(10) returned a fraction, not a decimal. This is because
my evaluator processes coefficients as fractions, in order to make
sure we don't loose any information as a result of casting to floating
point.
It was by building polynomials such as the above, and passing values
to them, that I developed the Bernoulli numbers:
>>> bernoulli.bernseries(14)
[1, (1/2.), (1/6.), 0, (-1/30.), 0, (1/42.), 0, (-1/30.), 0, (5/66.),
0, (-691/2730.), 0, (7/6.)]
The Matrix object, with subclass Sqmatrix (square matrix) works the
same way, with *, ** (power), +, - and / overrridden. The elements
of a matrix may be Fractions or Polys.
So the idea is to learn about mathematical objects by building them,
just as we build radios or other models to learn about their design
and structure. The result is, in this case, a primitive computer
algebra system.
In math class, we would spend more time talking about fractions,
lcm, gcd, the determinant of a matrix and so on, and less time
worrying about the syntax and infrastructure of Python, which
presumably they picked up somewhat earlier -- maybe in 8th grade,
whereas by this time we're in high school.
I gather you take a similar approach with Scheme, focusing
increasingly on the knowledge domain as time goes on, with
Scheme itself receiving less emphasis.
Kirby