In today’s Programming Praxis exercise, our goal is to implement some functions to do interval arithmetic. Let’s get started, shall we?

The plus and minus functions are trivial.

plus :: (Num a, Num b) => (a, b) -> (a, b) -> (a, b) plus (a,b) (c,d) = (a+c, b+d) minus :: (Num a, Num b) => (a, b) -> (b, a) -> (a, b) minus (a,b) (c,d) = (a-d, b-c)

As Chun Kin Lee pointed out, my initial attempt at removing duplication doesn’t work for ranges with negative numbers, so I had to go back to way mentioned in the original algorithm.

times :: (Num a, Ord a) => (a, a) -> (a, a) -> (a, a) times (a,b) (c,d) = let x = [a*c,a*d,b*c,b*d] in (minimum x, maximum x) divide :: (Fractional a, Ord a) => (a, a) -> (a, a) -> (a, a) divide (a,b) (c,d) = if c < 0 && d > 0 then error "divide by 0" else let x = [a/c,a/d,b/c,b/d] in (minimum x, maximum x)

Converting between bounded and centered intervals is also trivial.

toCenter :: Fractional a => (a, a) -> (a, a) toCenter (a,b) = ((a+b) / 2, (b-a) / 2) fromCenter :: Num a => (a, a) -> (a, a) fromCenter (a,b) = (a-b, a+b)

Some tests to see if everything is working properly:

main :: IO () main = do let x = (1,2) y = (3,4) print $ plus x y == (4,6) print $ minus x y == (-3,-1) print $ times x y == (3,8) print $ divide x y == (1/4,2/3) print $ divide x x == (1/2, 2) print $ toCenter x == (3/2,1/2) print $ fromCenter (3/2,1/2) == x

Everything seems to be working fine.