reactive-0.8.3: src/Data/AddBounds.hs
{-# OPTIONS_GHC -Wall #-}
----------------------------------------------------------------------
-- |
-- Module : Data.AddBounds
-- Copyright : (c) Conal Elliott 2008
-- License : BSD3
--
-- Maintainer : conal@conal.net
-- Stability : experimental
--
-- Add bounds to an ordered type
----------------------------------------------------------------------
module Data.AddBounds (AddBounds(..)) where
import Control.Applicative (pure,(<$>))
-- Testing
import Test.QuickCheck
import Test.QuickCheck.Checkers
-- | 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
-- Normally, I'd derive 'Ord' as well, but there's a sticky point. The
-- derived instance uses the default definition of 'min', which is uses
-- '(<=)' and thus cannot exploit any partial information. So, define our
-- own 'min' in terms of 'min' on @a@.
-- Examples:
-- (NoBound undefined) `min` (NoBound undefined) can return (NoBound _|_)
-- using this definition, but will not produce any output using the
-- default min.
--
-- (NoBound a) `min` (NoBound b) can return partial information from
-- a `min` b while the default implementation cannot.
instance Ord a => Ord (AddBounds a) where
MinBound <= _ = True
NoBound _ <= MinBound = False
NoBound a <= NoBound b = a <= b
NoBound _ <= MaxBound = True
MaxBound <= MaxBound = True
MaxBound <= _ = False -- given previous
MinBound `min` _ = MinBound
_ `min` MinBound = MinBound
NoBound a `min` NoBound b = NoBound (a `min` b)
u `min` MaxBound = u
MaxBound `min` v = v
MinBound `max` v = v
u `max` MinBound = u
NoBound a `max` NoBound b = NoBound (a `max` b)
_ `max` MaxBound = MaxBound
MaxBound `max` _ = MaxBound
instance Arbitrary a => Arbitrary (AddBounds a) where
arbitrary = frequency [ (1 ,pure MinBound)
, (10, NoBound <$> arbitrary)
, (1 ,pure MaxBound) ]
coarbitrary MinBound = variant 0
coarbitrary (NoBound a) = variant 1 . coarbitrary a
coarbitrary MaxBound = variant 2
instance (EqProp a, Eq a) => EqProp (AddBounds a) where
NoBound a =-= NoBound b = a =-= b
u =-= v = u `eq` v