packages feed

opml-conduit-0.1.0.0: Data/NotEmpty.hs

module Data.NotEmpty
  ( NE()
  , notEmpty
  , original
  , NotEmptyException(..)
  ) where

-- {{{ Imports
import           Control.Monad.Catch

import           Data.Semigroup

import           Test.QuickCheck
-- }}}

-- | For a monoid @s@, @NE s@ is @s@ without its neutral element 'mempty'.
newtype NE s = NE s

instance (Eq s) => Eq (NE s) where
  (NE a) == (NE b) = a == b

-- | @NE s@ is the semigroup derived from the monoid type @s@.
instance (Monoid s) => Semigroup (NE s) where
  (NE a) <> (NE b) = NE (a `mappend` b)

instance (Show s) => Show (NE s) where
  show (NE s) = show s

instance (Eq s, Monoid s, Arbitrary s) => Arbitrary (NE s) where
  arbitrary = NE <$> arbitrary `suchThat` (/= mempty)

-- | Smart constructor.
notEmpty :: (MonadThrow m, Eq s, Monoid s) => s -> m (NE s)
notEmpty s | s == mempty = throwM EmptyValue
           | otherwise   = return $ NE s

-- | Unwrap the underlying value.
original :: NE s -> s
original (NE s) = s


data NotEmptyException = EmptyValue deriving(Eq, Show)
instance Exception NotEmptyException