As a potential hybrid alternative (being a believer that all numeric
types beyond some "reasonable" minimally useful fixnum precision should
be enabled though optionally, although possibly typically, supported
libraries); might it be acceptable to consider modeling fixnums after
flonums whose operations are arguably closed over their domain bounded
by infinites; thereby some minimally required fixnum precision domain
may be similarly bounded by infinites and thereby closed over arithmetic
operations?
Thereby hypothetically to keep things real simple, it may even be
considered reasonable to bound fixnums by a sign-less Inf (i.e. NaN);
effectively enabling basic balanced fixnums to be defined as:
NaN -(2^(P-1)-1) 0 +(2^(P-1)-1) NaN
[where NaN is effectively = -2^(P-1), i.e. the pattern 10...]
Thereby any overflow may be relatively easily detected, and trapped
to return NaN, which in turn closes all subsequent operations to
corresponding return NaN.
Where then precision required beyond (for the sake of argument P=16)
and more efficient modulo and/or greater precision fixnum data types
may be enabled through either virtual or literal libraries, as would
be the support for extended exact and inexact data types and their
correspondingly overloaded operators?
Where further for the sake of argument, as I personally dislike the
proposed use of typed functions (i.e. fl+ etc.); I'd much prefer that
simple default semantics be defined for mixed data type operations.
For example something along the line of "operations will be performed
in the declared order at the precision of the most precise operand";
and enable the precision of the operation to be generically explicitly
controlled by enabling either the operator and/or operands to be cast
to an alternate explicit type, i.e.:
(+ 1/4 2.5) :: (+ 1/4 (<exact> 2.5)) :: (+ 1/4 5/2)
=> 11/4 <exact> ; as <exact> is most precise.
((<float> +) 1/4 2.5) :: (+ (<float> 1/4) (<float> 2.5)) :: (+ 0.25 2.5)
=> 2.75 <float> ; as both operands were effectively cast to <float>.
(+ (<fixed> 1/4) 2.5) :: (+ 0 2.5)
=> 2.5 <float> ; as <float> is most precise.
((<fixed> +) 1/4 2.5) :: (+ (<fixed> 1/4) (<fixed> 2.5)) :: (+ 0 2)
=> 2 <fixed> ; as both operands were effectively cast to <fixed>.