Although not an answer to the question (still hope there is some clever way (as always in haskell...)). For reusing determining lower and upper bounds I came with something like this:
data ValueRange = MkValueRange { minValue :: Double, maxValue :: Double }
instance Show ValueRange where
show (MkValueRange minV maxV) = "ValueRange(" ++ show minV ++ ", " ++ show maxV ++ ")"
fmap2 :: (Double -> Double -> Double) -> ValueRange -> ValueRange -> ValueRange
fmap2 f (MkValueRange minA maxA) (MkValueRange minB maxB) =
MkValueRange (minimum results) (maximum results)
where
results = [ f x y | x <- [minA, maxA], y <- [minB, maxB] ]
(<+>) :: ValueRange -> ValueRange -> ValueRange
(<+>) = fmap2 (+)
(<->) :: ValueRange -> ValueRange -> ValueRange
(<->) = fmap2 (-)
(<*>) :: ValueRange -> ValueRange -> ValueRange
(<*>) = fmap2 (*)
(</>) :: ValueRange -> ValueRange -> ValueRange
(</>) = fmap2 (/)
example1 :: ValueRange
example1 = MkValueRange 10 20 <+> MkValueRange 5 15