module Data.Limit
    ( Limit(Bounded,Unbounded)
    , isBounded
    , isUnbounded
    , fromBounded
    , fromLimit
    ) where

import Control.Monad ( liftM2 )

data Limit a = Bounded a | Unbounded
    deriving (Eq, Read, Show)

instance Ord a => Ord (Limit a) where
    x <= y = fromLimit (y == Unbounded) (liftM2 (<=) x y)

instance Functor Limit where
    fmap _ Unbounded = Unbounded
    fmap f (Bounded a) = Bounded (f a)

instance Monad Limit where
    Unbounded >>= _ = Unbounded
    (Bounded x) >>= k = k x

    Unbounded >> _ = Unbounded
    (Bounded _) >> k = k

    return = Bounded
    fail _ = Unbounded

isBounded :: Limit a -> Bool
isBounded Unbounded = False
isBounded _ = True

isUnbounded :: Limit a -> Bool
isUnbounded = not . isBounded

fromBounded :: Limit a -> a
fromBounded Unbounded = error "Limit.fromBounded: Unbounded" -- YOUR BAD
fromBounded (Bounded x) = x

fromLimit :: a -> Limit a -> a
fromLimit d Unbounded = d
fromLimit _ (Bounded x) = x