views:

352

answers:

6

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?

+6  A: 

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
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
Nooo, please don't put a type class constraint on a data declaration! :-)
Martijn
+8  A: 

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..])

MatrixFrog
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
Darn. I knew I shouldn't have claimed a program would run forever after watching it run for a finite amount of time.
MatrixFrog
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
+4  A: 

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 Krjuchkov
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
Huh, actually I didn't know this, thanks.
Denis Krjuchkov
+1  A: 

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
+1  A: 
infinity = read "Infinity"
newacct
+1  A: 

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