31

I'm trying to implement a data structure where if I had the use of infinity for numerical comparison purposes, it would simply things greatly. Note this isn't maxBound/minBound, because a value can be <= maxbound, but all values would be < infinity.

No hope?

remdezx
  • 2,939
  • 28
  • 49
me2
  • 3,069
  • 2
  • 26
  • 33

9 Answers9

30

Well how about that! It turns out if you just type 1/0 it returns Infinity! On ghci:

Prelude> 1/0
Infinity
Prelude> :t 1/0
1/0 :: (Fractional t) => t
Prelude> let inf=1/0
Prelude> filter (>=inf) [1..]

and then of course it runs forever, never finding a number bigger than infinity. (But see ephemient's comments below on the actual behavior of [1..])

Tyler
  • 21,762
  • 11
  • 61
  • 90
  • 4
    IMO, `encodeFloat (floatRadix 0 - 1) (snd $ floatRange 0)` is a better way to get `Infinity` (with type `(RealFrac a) => a`). That being said, because of floating-point imprecision `[1..]` is never going to get past a finite upper bound, so what you have here is a poor demonstration. – ephemient Mar 01 '10 at 17:35
  • 9
    Darn. I knew I shouldn't have claimed a program would run forever after watching it run for a finite amount of time. – Tyler Mar 01 '10 at 18:35
  • 4
    You misunderstand. At some point, the tail will just be `[x, x, x, x, x, ..]`, because floating `x+1 == x` when `x` is large enough, even though there exist higher, finite `y` (for example, `encodeFloat (floatRadix 0 - 1) (snd (floatRange 0) - 1)`). Obviously `x < y < inf`; my point was that this isn't a good demonstration of infinity. – ephemient Mar 01 '10 at 20:26
  • This can also be written as `recip 0` – hololeap Oct 03 '16 at 04:12
  • @ephemient I believe that is incorrect, though I can't say if it was true when you made that comment. The current implementations of `Enum` for floating point types take that issue into account and will happily sail right past the number you are talking about (the `x` where `x + 1 == x`). – HTNW Dec 19 '18 at 03:36
29
infinity = read "Infinity"
newacct
  • 119,665
  • 29
  • 163
  • 224
  • 1
    I think this is the best answer if the code is floating-point. People tend to forget about floating-point infinity. – migle Sep 19 '14 at 13:52
17

Maybe you want a Maybe type?

data Infinite a = Infinite | Only a

then write a Num instance for Num a => Infinite a, with the numeric rules you need.

Don Stewart
  • 137,316
  • 36
  • 365
  • 468
  • 2
    Getting obvious there is no solution, so I've basically adopt your approach: `data Num a => Inf a = NegInf | Val a | PosInf`. Thanks for your help. – me2 Mar 01 '10 at 09:34
  • 33
    Nooo, please don't put a type class constraint on a data declaration! :-) – Martijn Mar 01 '10 at 20:25
10

Try something like this. However, to get Num operations (like + or -) you will need to define Num instance for Infinitable a type. Just like I've done it for Ord class.

data Infinitable a = Regular a | NegativeInfinity | PositiveInfinity deriving (Eq, Show)

instance Ord a => Ord (Infinitable a) where
    compare NegativeInfinity NegativeInfinity = EQ
    compare PositiveInfinity PositiveInfinity = EQ
    compare NegativeInfinity _ = LT
    compare PositiveInfinity _ = GT
    compare _ PositiveInfinity = LT
    compare _ NegativeInfinity = GT
    compare (Regular x) (Regular y) = compare x y    

main =
    let five = Regular 5
        pinf = PositiveInfinity::Infinitable Integer
        ninf = NegativeInfinity::Infinitable Integer
        results = [(pinf > five), (ninf < pinf), (five > ninf)]
    in
        do putStrLn (show results)
Denis K
  • 1,448
  • 1
  • 10
  • 17
  • 21
    By the way: if you define your `Infinitable` data type with the `NegativeInfinity` case first, then the `Regular` and the `PositiveInfinity` last, you can derive `Ord` for free. (If you did it this way to give a relatively simple example, please disregard this comment!) – yatima2975 Mar 01 '10 at 10:43
6
λ: let infinity = (read "Infinity")::Double
λ: infinity > 1e100
True
λ: -infinity < -1e100
True
3

Take a look at my RangedSets library, which does exactly this in a very general way. I defined a "Boundary" type so that a value of type "Boundary a" is always either above or below any given "a". Boundaries can be "AboveAll", "BelowAll", "Above x" and "Below x".

Paul Johnson
  • 17,438
  • 3
  • 42
  • 59
2

You can work with the ieee754 package which offers an IEEE typeclass. This typeclass has an infinity member. The typeclass is implemented for Float, Double, CFloat and CDouble.

You thus install the ieee-754 package, and then obtain positive infinity (or negative infinity) with:

ghci> import Numeric.IEEE
ghci> infinity :: Double
Infinity
ghci> -infinity :: Double
-Infinity

For Floats, Doubles, etc. it is implemented as [src]:

    infinity = 1/0
Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
1

If your use case is that you have boundary conditions that sometimes need to be checked, but sometimes not, you can solve it like this:

type Bound a = Maybe a

withinBounds :: (Num a, Ord a) => Bound a -> Bound a -> a -> Bool
withinBounds lo hi v = maybe True (<=v) lo && maybe True (v<=) hi
MtnViewMark
  • 5,120
  • 2
  • 20
  • 29
1

There is a more principled approach based on an idea from non-standard analysis. Given a totally ordered ring R of characteristic zero, you can consider the Laurent ring R[inf,1/inf] with the natural lexicographic total ordering. For example, you have:

for all x>0 in R,
.. -inf < -x < -d < -d^2 < .. < 0 < .. < d^2 < d < x < inf < inf^2 < .. 
where d = 1/inf.

This way the Laurent ring R[inf,1/inf] is again a totally ordered Z-algebra, i.e. an instance of Num, with other niceties you possibly want, including +/-infinity, +/-infinitesimal, second-order infinitesimals, etc.. But note that it's not Archimedian and induction will no longer work, which is a sort of second-order arithmetic. For implementation take a look at this example. As in the comment in the code this construction should work for other algebras, such as the list monad. You can think of lists where two elements are "infinitely close" "second-order infinitely far away" etc. (which leads to a generalization of rose trees.)

mnish
  • 385
  • 2
  • 11