
Dylan Thurston writes: : | (A question in the above context is whether the literal '0' should | be interpreted as 'fromInteger (0::Integer)' or as 'zero'. | Opinions?) Opinions? Be careful what you wish for. ;-) In a similar discussion last year, I was making wistful noises about subtyping, and one of Marcin's questions http://www.mail-archive.com/haskell-cafe@haskell.org/msg00125.html was whether the numeric literal 10 should have type Int8 (2's complement octet) or Word8 (unsigned octet). At the time I couldn't give a wholly satisfactory answer. Since then I've read the oft-cited paper "On Understanding Types, Data Abstraction, and Polymorphism" (Cardelli & Wegner, ACM Computing Surveys, Dec 1985), which suggests a nice answer: give the numeric literal 10 the range type 10..10, which is defined implicitly and is a subtype of both -128..127 (Int8) and 0..255 (Word8). The differences in arithmetic on certain important range types could be represented by multiple primitive functions (or perhaps foreign functions, through the FFI): primAdd :: Integer -> Integer -> Integer -- arbitrary precision primAdd8s :: Int8 -> Int8 -> Int8 -- overflow at -129, 128 primAdd8u :: Word8 -> Word8 -> Word8 -- overflow at -1, 256 -- etc. instance Additive Integer where zero = 0 (+) = primAdd ...with similar instances for the integer subrange types which may overflow. These other instances would belong outside the standard Prelude, so that the ambiguity questions don't trouble people (such as beginners) who don't care about the space and time advantages of fixed precision integers. Subtyping offers an alternative approach to handling arithmetic overflows: - Use only arbitrary precision arithmetic. - When calculated result *really* needs to be packed into a fixed precision format, project it (or treat it down, etc., whatever's your preferred name), so that overflows are represented as Nothing. For references to other uses of class Subtype see: http://www.mail-archive.com/haskell@haskell.org/msg07303.html For a reference to some unification-driven rewrites, see: http://www.mail-archive.com/haskell@haskell.org/msg07327.html Marcin 'Qrczak' Kowalczyk writes: : | Assuming that Ints can be implicitly converted to Doubles, is the | function | f :: Int -> Int -> Double -> Double | f x y z = x + y + z | ambiguous? Because there are two interpretations: | f x y z = realToFrac x + realToFrac y + z | f x y z = realToFrac (x + y) + z | | Making this and similar case ambiguous means inserting lots of explicit | type signatures to disambiguate subexpressions. | | Again, arbitrarily choosing one of the alternatives basing on some | set of weighting rules is dangerous, I don't think the following disambiguation is too arbitrary: x + y + z -- as above --> (x + y) + z -- left-associativity of (+) --> realToFrac (x + y) + z -- injection (or treating up) done -- conservatively, i.e. only where needed Regards, Tom