Ivory: Numbers In Scheme
    ┌─┐ ┌──┐ ┌─┐
    │ └─┘  └─┘ │
    │ integer  │
    ├──────────┤
    │ rational │
    ├──────────┤
    │   real   │
    ├──────────┤
    │ complex  │
    ├──────────┤
    │  number  │
────┴──────────┴────Scheme uses the asterisk * for
multiplication, since it’s easy to type on a standard US keyboard. I
prefer the usual × symbol, for
clarity. Hence we’ll define × to
be *, so
that both symbols will mean multiplication:
(define × *)Numbers in Scheme can be exact or inexact. Ivory
is only concerned with exact numbers,
so we’ll ignore the latter. Scheme arranges its types in a “numerical
tower”, where each level is a super-set of the ones above,
including:
- integer: Whole numbers, positive and negative.
- rational: All fractions, positive and negative.
- real: This supposedly includes the whole “number line”, but is actually rather silly since almost all of the “real numbers” can’t be represented.
- complex: This uses a clever trick to represent square roots of negative numbers. If you’ve encountered it before, great; if not, don’t worry since Ivory does not include this level (we instead define a mezzanine inside the- geometriclevel)
- number: This is the top level, containing every numeric value.
These are cumulative, so an integer like -42 is also a
rational (e.g. you can think of
it like -42/1), a
real and a complex (like -42+0i,
if you know what that means).
This basic framework is the inspiration for Ivory.
Numbers in Racket
        ┌─┐ ┌──┐ ┌─┐
        │ └─┘  └─┘ │
        │   zero   │
       ┌┴──────────┴┐
       │  natural   │
      ┌┴────────────┴┐
      │   integer    │
     ┌┴──────────────┴┐
     │    rational    │
     ├────────────────┤
     │      real      │
    ┌┴────────────────┴┐
    │     complex      │
    ├──────────────────┤
    │      number      │
────┴──────────────────┴────complex is another name for number, and real is another name for rational (for exact numbers,
at least).
Racket already extends Scheme’s standard numerical tower, and pins-down some details that Scheme leaves open. In particular:
- Scheme allows levels between complexandnumber, but Racket doesn’t provide any.
- Racket’s foundational numbertype adds nothing else tocomplex(they’re just synonyms)
- The only exactnumbers in Racket’sreallevel arerational. Hence, as far as Ivory is concerned, those levels are the same.
Racket does add some “attic levels”, which are strict
subsets of integer:
- naturalis a sub-set of- integerwithout negatives. It is closed under- +,- ×,- gcd,- lcm,- max,- min, etc.; as well as- quotientand- remainderexcluding the divisor- 0, and- exptexcluding- (expt 0 0).
- zerois a sub-set of- naturalcontaining only- 0. It is closed under- +,- ×,- gcd,- lcm,- max,- min, etc.
Even more fine-grained structure is described
in the Typed Racket documentation (e.g. byte is a subset of natural between 0 and 255) but Ivory
does not make such size-based distinctions.
Code
This post defines Racket code, including a RackCheck test suite to check the claims we make on this page. Here’s a URI containing all of the generated code:
Test results
raco test: (submod (file "num.rkt") test)
  ✓ property ×-matches-* passed 100 tests.
  ✓ property integer?-implies-rational? passed 100 tests.
  ✓ property rational?-implies-number? passed 100 tests.
  ✓ property natural?-implies-integer? passed 100 tests.
  ✓ property natural-is-closed passed 100 tests.
26 tests passed