Re: Bounded and floating types

Oops -- I'd incorrectly assumed that Haskell guarantees Float & Double to
have infinities. Thanks, - Conal
On Dec 2, 2007 9:50 AM, Lennart Augustsson
But that only makes sense for floating point types that have -Infinity and +Infinity.
On Dec 2, 2007 5:39 PM, Conal Elliott
wrote: Currently Float & Double do not have standard Bounded instances. Is there any reason not to use the following?
instance Bounded Float where { minBound = -1/0; maxBound = 1/0 } instance Bounded Double where { minBound = -1/0; maxBound = 1/0 }
If I don't hear objections, I'll submit a ticket and re-send a proposal note.
- Conal
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

I'm using the bounds for event occurrence times. Or, from another angle, for times associated with when values can become known. Pure values have time minBound, while eternally unknowable values (non-occurring events) have time maxBound. Hm. Now that I put it that way, I realize that I don't want to use existing minBound and maxBound if they're finite. (My event types are temporally polymorphic.) I'm mainly interested in Float/Double times, which have infinities in practice but apparently not guaranteed by the language standard. I guess I'll either (a) bake in Double (temporally monomorphic) and rely on infinities not guaranteed by the standard, or (b) keep temporal polymorphism and add infinities to time parameter. For now, (b). Cheers, - Conal On Dec 2, 2007 1:08 PM, Henning Thielemann < lemming@henning-thielemann.de> wrote:
On Sun, 2 Dec 2007, Conal Elliott wrote:
Oops -- I'd incorrectly assumed that Haskell guarantees Float & Double to have infinities. Thanks, - Conal
Aside from that - what do you intend to do with the bounds?

Conal Elliott wrote:
Pure values have time minBound, while eternally unknowable values (non-occurring events) have time maxBound. Hm. Now that I put it that way, I realize that I don't want to use existing minBound and maxBound if they're finite. (My event types are temporally polymorphic.) I'm mainly interested in Float/Double times, which have infinities in practice but apparently not guaranteed by the language standard.
And even in the current implementation with infinities, maxBound would be NaN, not +Inf: Prelude> let z = 0 :: Double Prelude> 0 / z NaN Prelude> 1 / z Infinity Prelude> (-1) / z -Infinity Prelude> (0 / z) `compare` (1 / z) GT Prelude> (0 / z) `compare` ((-1) / z) GT This is another case where the linear ordering provided by Ord has an arbitrary flavour, since the type of IEEE doubles does not have a ``natural'' linear ordering. (And I consider this as independent of whether the IEEE standard prescribes this ordering or not.) For Conal it is probably going to be the question whether he identifies a different interface as serving his purposes better (supported by ``I don't want to use existing minBound and maxBound if they're finite'' and ``For now, (b)'') or whether he thinks that Bounded ``feels right'' for his purposes, and does a newtype for Double without NaN, with the infinities as bounds. My arguments consistently assume the following specification: \begin{spec} forall a . (Ord a, Bounded a) => forall x :: a . minBound <= x && x <= maxBound \end{spec} (I.e., if a type has both Ord and Bounded instances, then for all |x| of that type, |minBound <= x| and |x <= maxBound| are |True| if defined. Normally one would expect, as part of the specification of Ord, that |x <= y| is defined at least when both |x| and |y| are fully defined, i.e., do not contain |undefined| anywhere. So I would not accept |(Nan <= Infinity) = undefined|, but would insist on mapping Nan itself to undefined. ) Yitzchak Gale pointed out:
Where are these axioms? I only see the Haddocks in the Prelude:
"Ord is not a superclass of Bounded since types that are not totally ordered may also have upper and lower bounds."
This does not contradict my specification, but also does not imply it, although it could be argued that the sentence | The Bounded class is used to name the upper and lower limits of a type. might be understood to imply it --- supported by the discussion. I think the absence of such a specification would be very bad practice, since it relegates Bounded to just provide two arbitrary elements about which nothing can be assumed by any library function. (And I would prefer to have Ord as superclass of Bounded.) While we are looking at the Prelude --- it also has the following: | For any type that is an instance of class Bounded as well as Enum, the | following should hold: | | * The calls succ maxBound and pred minBound should result in a runtime | error. | * fromEnum and toEnum should give a runtime error if the result value is | not representable in the result type. For example, toEnum 7 :: Bool is | an error. | * enumFrom and enumFromThen should be defined with an implicit bound, | thus: | | enumFrom x = enumFromTo x maxBound | enumFromThen x y = enumFromThenTo x y bound | where | bound | fromEnum y >= fromEnum x = maxBound | | otherwise = minBound However, GHC-6.6.1 says: Prelude> succ (1/z) Infinity Prelude> succ (0/z) NaN Prelude> succ ((-1)/z) -Infinity Prelude> pred ((-1)/z) -Infinity So Double cannot be an instance of Bounded... (Aside: Notice: Prelude> succ (maxBound :: Int) *** Exception: Prelude.Enum.succ{Int}: tried to take `succ' of maxBound Prelude> 1 + (maxBound :: Int) -2147483648 so don't use (1 +) unless you want wrap-around. ) And don't use succ, pred, fromEnum, and toEnum unless you are prepared to have run-time errors --- the specification of these run-time errors does not even require an Eq instance, so there is no general way to catch or prevent these. I think a MonadError-based interface would be much better (I also believe that |fail| should not be a member of the class Monad). (I also agree with the Indexable argument, but consider that issue as separate.) Wolfram

On Tue, Dec 04, 2007 at 02:21:11AM -0000, kahl@cas.mcmaster.ca wrote:
Conal Elliott wrote:
Pure values have time minBound, while eternally unknowable values (non-occurring events) have time maxBound. Hm. Now that I put it that way, I realize that I don't want to use existing minBound and maxBound if they're finite. (My event types are temporally polymorphic.) I'm mainly interested in Float/Double times, which have infinities in practice but apparently not guaranteed by the language standard.
And even in the current implementation with infinities, maxBound would be NaN, not +Inf:
Prelude> let z = 0 :: Double Prelude> 0 / z NaN Prelude> 1 / z Infinity Prelude> (-1) / z -Infinity Prelude> (0 / z) `compare` (1 / z) GT Prelude> (0 / z) `compare` ((-1) / z) GT
This is another case where the linear ordering provided by Ord has an arbitrary flavour, since the type of IEEE doubles does not have a ``natural'' linear ordering. (And I consider this as independent of whether the IEEE standard prescribes this ordering or not.)
It's rather worse than that. Prelude> let nan = 0/0 Prelude> nan > nan False Prelude> nan < nan False Prelude> nan == nan False Double isn't even totally ordered! Stefan

Stefan O'Rear
It's rather worse than that.
Prelude> let nan = 0/0 Prelude> nan > nan False Prelude> nan < nan False Prelude> nan == nan False
And this begs the question: Prelude> compare nan nan GT So while NaN is greater than itself, it is at the same time not greater than itself? -k -- If I haven't seen further, it is by standing in the footprints of giants

On Wed, Dec 05, 2007 at 09:18:38AM +0100, Ketil Malde wrote:
Stefan O'Rear
writes: It's rather worse than that.
Prelude> let nan = 0/0 Prelude> nan > nan False Prelude> nan < nan False Prelude> nan == nan False
And this begs the question:
Prelude> compare nan nan GT
So while NaN is greater than itself, it is at the same time not greater than itself?
There is a case to be made for Ord Double to use the trapping comparison operators. Stefan

Wolfram wrote:
My arguments consistently assume the following specification: \begin{spec} forall a . (Ord a, Bounded a) => forall x :: a . minBound <= x && x <= maxBound \end{spec}
That sounds like a great thing to suggest for Haskell'. It is not true currently. Ord and Bounded are independent of each other. Current discussions on this list make it clear that forcibly enforcing such a restriction, e.g. by introducing Bounded instances in libraries, would break people's existing programs. Your restriction implies, among other things, that Ord may only be used for natural universal orderings of a type, not for arbitrary artificial orderings introduced for technical reasons. Because otherwise, why restrict people from using a natural Bounded instance if there is one, or a Bounded instance that is needed for some other technical reason? A good migration path towards your idea would be to fix the current most prominent offenders, the Data.<collection> modules, by providing an additional version of each that uses Indexable instead of Ord for artificial orderings, as suggest by Henning. And, of course, there is nothing to stop us from suggesting that people adhere to your specification by adding it to the documentation. I wrote:
Where are these axioms?
...it could be argued that the sentence: "The Bounded class is used to name the upper and lower limits of a type." might be understood to imply it
Given the current usage of Ord in the libraries, there is no reason to think that the upper and lower limits *of a type* necessarily have anything to do with Ord. -Yitz

On Mon, 3 Dec 2007, Conal Elliott wrote:
I'm using the bounds for event occurrence times. Or, from another angle, for times associated with when values can become known. Pure values have time minBound, while eternally unknowable values (non-occurring events) have time maxBound. Hm. Now that I put it that way, I realize that I don't want to use existing minBound and maxBound if they're finite. (My event types are temporally polymorphic.) I'm mainly interested in Float/Double times, which have infinities in practice but apparently not guaranteed by the language standard. I guess I'll either (a) bake in Double (temporally monomorphic) and rely on infinities not guaranteed by the standard, or (b) keep temporal polymorphism and add infinities to time parameter. For now, (b).
Since you cannot rely on the existence of an infinity value for a floating point type with a particular behaviour - you can simply define you own type: data InfinityClosure a = NegativeInfinity | Finite a | PositiveInfinity

Thanks. That's exactly what I've done:
-- | Wrap a type into one having new least and greatest elements,
-- preserving the existing ordering.
data AddBounds a = MinBound | NoBound a | MaxBound
deriving (Eq, Ord, Read, Show)
instance Bounded (AddBounds a) where
minBound = MinBound
maxBound = MaxBound
Looks like a generally useful tool. Is there any interest in seeing it
added to a standard lib?
- Conal
On Dec 4, 2007 4:46 AM, Henning Thielemann
On Mon, 3 Dec 2007, Conal Elliott wrote:
I'm using the bounds for event occurrence times. Or, from another angle, for times associated with when values can become known. Pure values have time minBound, while eternally unknowable values (non-occurring events) have time maxBound. Hm. Now that I put it that way, I realize that I don't want to use existing minBound and maxBound if they're finite. (My event types are temporally polymorphic.) I'm mainly interested in Float/Double times, which have infinities in practice but apparently not guaranteed by the language standard. I guess I'll either (a) bake in Double (temporally monomorphic) and rely on infinities not guaranteed by the standard, or (b) keep temporal polymorphism and add infinities to time parameter. For now, (b).
Since you cannot rely on the existence of an infinity value for a floating point type with a particular behaviour - you can simply define you own type:
data InfinityClosure a = NegativeInfinity | Finite a | PositiveInfinity
participants (6)
-
Conal Elliott
-
Henning Thielemann
-
kahl@cas.mcmaster.ca
-
Ketil Malde
-
Stefan O'Rear
-
Yitzchak Gale