refined-0.2.3.0: Refinement types with static and runtime checking

Safe HaskellNone
LanguageHaskell2010

Refined

Contents

Description

In type theory, a refinement type is a type endowed with a predicate which is assumed to hold for any element of the refined type.

This library allows one to capture the idea of a refinement type using the Refined type. A Refined p x wraps a value of type x, ensuring that it satisfies a type-level predicate p.

A simple introduction to this library can be found here: http://nikita-volkov.github.io/refined/

Synopsis

Refined

data Refined p x Source #

A refinement type, which wraps a value of type x, ensuring that it satisfies a type-level predicate p.

The only ways that this library provides to construct a value of type Refined are with the 'refine-' family of functions, because the use of the newtype constructor gets around the checking of the predicate. This restriction on the user makes unrefine safe.

If you would really like to construct a Refined value without checking the predicate, use unsafeCoerce.

Instances

Foldable (Refined p) Source # 

Methods

fold :: Monoid m => Refined p m -> m #

foldMap :: Monoid m => (a -> m) -> Refined p a -> m #

foldr :: (a -> b -> b) -> b -> Refined p a -> b #

foldr' :: (a -> b -> b) -> b -> Refined p a -> b #

foldl :: (b -> a -> b) -> b -> Refined p a -> b #

foldl' :: (b -> a -> b) -> b -> Refined p a -> b #

foldr1 :: (a -> a -> a) -> Refined p a -> a #

foldl1 :: (a -> a -> a) -> Refined p a -> a #

toList :: Refined p a -> [a] #

null :: Refined p a -> Bool #

length :: Refined p a -> Int #

elem :: Eq a => a -> Refined p a -> Bool #

maximum :: Ord a => Refined p a -> a #

minimum :: Ord a => Refined p a -> a #

sum :: Num a => Refined p a -> a #

product :: Num a => Refined p a -> a #

Eq x => Eq (Refined p x) Source # 

Methods

(==) :: Refined p x -> Refined p x -> Bool #

(/=) :: Refined p x -> Refined p x -> Bool #

Ord x => Ord (Refined p x) Source # 

Methods

compare :: Refined p x -> Refined p x -> Ordering #

(<) :: Refined p x -> Refined p x -> Bool #

(<=) :: Refined p x -> Refined p x -> Bool #

(>) :: Refined p x -> Refined p x -> Bool #

(>=) :: Refined p x -> Refined p x -> Bool #

max :: Refined p x -> Refined p x -> Refined p x #

min :: Refined p x -> Refined p x -> Refined p x #

(Read x, Predicate p x) => Read (Refined p x) Source # 
Show x => Show (Refined p x) Source # 

Methods

showsPrec :: Int -> Refined p x -> ShowS #

show :: Refined p x -> String #

showList :: [Refined p x] -> ShowS #

Lift x => Lift (Refined p x) Source # 

Methods

lift :: Refined p x -> Q Exp #

Creation

refine :: Predicate p x => x -> Either RefineException (Refined p x) Source #

A smart constructor of a Refined value. Checks the input value at runtime.

refineThrow :: (Predicate p x, MonadThrow m) => x -> m (Refined p x) Source #

Constructs a Refined value at run-time, calling throwM if the value does not satisfy the predicate.

refineFail :: (Predicate p x, MonadFail m) => x -> m (Refined p x) Source #

Constructs a Refined value at run-time, calling fail if the value does not satisfy the predicate.

refineError :: (Predicate p x, MonadError RefineException m) => x -> m (Refined p x) Source #

Constructs a Refined value at run-time, calling throwError if the value does not satisfy the predicate.

unsafeRefine :: Predicate p x => x -> Refined p x Source #

Constructs a Refined value at run-time, calling error if the value does not satisfy the predicate.

WARNING: this function is not total!

refineTH :: (Predicate p x, Lift x) => x -> Q (TExp (Refined p x)) Source #

Constructs a Refined value at compile-time using -XTemplateHaskell.

For example:

>>> $$(refineTH 23) :: Refined Positive Int
Refined 23

Here's an example of an invalid value:

>>> $$(refineTH 0) :: Refined Positive Int
<interactive>:6:4:
    Value is not greater than 0
    In the Template Haskell splice $$(refineTH 0)
    In the expression: $$(refineTH 0) :: Refined Positive Int
    In an equation for ‘it’:
        it = $$(refineTH 0) :: Refined Positive Int

If it's not evident, the example above indicates a compile-time failure, which means that the checking was done at compile-time, thus introducing a zero runtime overhead compared to a plain value construction.

Consumption

unrefine :: Refined p x -> x Source #

Extracts the refined value.

Predicate

class Typeable p => Predicate p x where Source #

A typeclass which defines a runtime interpretation of a type-level predicate p for type x.

Minimal complete definition

validate

Methods

validate :: Monad m => p -> x -> RefineT m () Source #

Check the value x according to the predicate p, producing an error string if the value does not satisfy.

Instances

(IsList t, Ord (Item t)) => Predicate Descending t Source # 

Methods

validate :: Monad m => Descending -> t -> RefineT m () Source #

(IsList t, Ord (Item t)) => Predicate Ascending t Source # 

Methods

validate :: Monad m => Ascending -> t -> RefineT m () Source #

(Eq x, Num x, KnownNat n) => Predicate (NotEqualTo n) x Source # 

Methods

validate :: Monad m => NotEqualTo n -> x -> RefineT m () Source #

(Eq x, Num x, KnownNat n) => Predicate (EqualTo n) x Source # 

Methods

validate :: Monad m => EqualTo n -> x -> RefineT m () Source #

(Ord x, Num x, KnownNat n) => Predicate (To n) x Source # 

Methods

validate :: Monad m => To n -> x -> RefineT m () Source #

(Ord x, Num x, KnownNat n) => Predicate (From n) x Source # 

Methods

validate :: Monad m => From n -> x -> RefineT m () Source #

(Ord x, Num x, KnownNat n) => Predicate (GreaterThan n) x Source # 

Methods

validate :: Monad m => GreaterThan n -> x -> RefineT m () Source #

(Ord x, Num x, KnownNat n) => Predicate (LessThan n) x Source # 

Methods

validate :: Monad m => LessThan n -> x -> RefineT m () Source #

(Predicate p x, Typeable * p) => Predicate (Not p) x Source # 

Methods

validate :: Monad m => Not p -> x -> RefineT m () Source #

(Foldable t, KnownNat n) => Predicate (SizeEqualTo n) (t a) Source # 

Methods

validate :: Monad m => SizeEqualTo n -> t a -> RefineT m () Source #

(Foldable t, KnownNat n) => Predicate (SizeGreaterThan n) (t a) Source # 

Methods

validate :: Monad m => SizeGreaterThan n -> t a -> RefineT m () Source #

(Foldable t, KnownNat n) => Predicate (SizeLessThan n) (t a) Source # 

Methods

validate :: Monad m => SizeLessThan n -> t a -> RefineT m () Source #

(Ord x, Num x, KnownNat mn, KnownNat mx, (<=) mn mx) => Predicate (FromTo mn mx) x Source # 

Methods

validate :: Monad m => FromTo mn mx -> x -> RefineT m () Source #

(Predicate l x, Predicate r x, Typeable * l, Typeable * r) => Predicate (Or l r) x Source # 

Methods

validate :: Monad m => Or l r -> x -> RefineT m () Source #

(Predicate l x, Predicate r x, Typeable * l, Typeable * r) => Predicate (And l r) x Source # 

Methods

validate :: Monad m => And l r -> x -> RefineT m () Source #

Logical predicates

data Not p Source #

The negation of a predicate.

Instances

(Predicate p x, Typeable * p) => Predicate (Not p) x Source # 

Methods

validate :: Monad m => Not p -> x -> RefineT m () Source #

data And l r Source #

The conjunction of two predicates.

Instances

(Predicate l x, Predicate r x, Typeable * l, Typeable * r) => Predicate (And l r) x Source # 

Methods

validate :: Monad m => And l r -> x -> RefineT m () Source #

type (&&) = And infixr 3 Source #

The conjunction of two predicates.

data Or l r Source #

The disjunction of two predicates.

Instances

(Predicate l x, Predicate r x, Typeable * l, Typeable * r) => Predicate (Or l r) x Source # 

Methods

validate :: Monad m => Or l r -> x -> RefineT m () Source #

type (||) = Or infixr 2 Source #

The disjunction of two predicates.

Numeric predicates

data LessThan (n :: Nat) Source #

A Predicate ensuring that the value is less than the specified type-level number.

Instances

(Ord x, Num x, KnownNat n) => Predicate (LessThan n) x Source # 

Methods

validate :: Monad m => LessThan n -> x -> RefineT m () Source #

(<=) n m => Weaken (LessThan n) (To m) Source # 

Methods

weaken :: Refined (LessThan n) x -> Refined (To m) x Source #

(<=) n m => Weaken (LessThan n) (LessThan m) Source # 

Methods

weaken :: Refined (LessThan n) x -> Refined (LessThan m) x Source #

data GreaterThan (n :: Nat) Source #

A Predicate ensuring that the value is greater than the specified type-level number.

Instances

(Ord x, Num x, KnownNat n) => Predicate (GreaterThan n) x Source # 

Methods

validate :: Monad m => GreaterThan n -> x -> RefineT m () Source #

(<=) m n => Weaken (GreaterThan n) (From m) Source # 

Methods

weaken :: Refined (GreaterThan n) x -> Refined (From m) x Source #

(<=) m n => Weaken (GreaterThan n) (GreaterThan m) Source # 

data From (n :: Nat) Source #

A Predicate ensuring that the value is greater than or equal to the specified type-level number.

Instances

(Ord x, Num x, KnownNat n) => Predicate (From n) x Source # 

Methods

validate :: Monad m => From n -> x -> RefineT m () Source #

(<=) m n => Weaken (From n) (From m) Source # 

Methods

weaken :: Refined (From n) x -> Refined (From m) x Source #

(<=) m n => Weaken (GreaterThan n) (From m) Source # 

Methods

weaken :: Refined (GreaterThan n) x -> Refined (From m) x Source #

(<=) p n => Weaken (FromTo n m) (From p) Source # 

Methods

weaken :: Refined (FromTo n m) x -> Refined (From p) x Source #

data To (n :: Nat) Source #

A Predicate ensuring that the value is less than or equal to the specified type-level number.

Instances

(Ord x, Num x, KnownNat n) => Predicate (To n) x Source # 

Methods

validate :: Monad m => To n -> x -> RefineT m () Source #

(<=) n m => Weaken (To n) (To m) Source # 

Methods

weaken :: Refined (To n) x -> Refined (To m) x Source #

(<=) n m => Weaken (LessThan n) (To m) Source # 

Methods

weaken :: Refined (LessThan n) x -> Refined (To m) x Source #

(<=) m q => Weaken (FromTo n m) (To q) Source # 

Methods

weaken :: Refined (FromTo n m) x -> Refined (To q) x Source #

data FromTo (mn :: Nat) (mx :: Nat) Source #

A Predicate ensuring that the value is within an inclusive range.

Instances

(Ord x, Num x, KnownNat mn, KnownNat mx, (<=) mn mx) => Predicate (FromTo mn mx) x Source # 

Methods

validate :: Monad m => FromTo mn mx -> x -> RefineT m () Source #

(<=) m q => Weaken (FromTo n m) (To q) Source # 

Methods

weaken :: Refined (FromTo n m) x -> Refined (To q) x Source #

(<=) p n => Weaken (FromTo n m) (From p) Source # 

Methods

weaken :: Refined (FromTo n m) x -> Refined (From p) x Source #

((<=) p n, (<=) m q) => Weaken (FromTo n m) (FromTo p q) Source # 

Methods

weaken :: Refined (FromTo n m) x -> Refined (FromTo p q) x Source #

data EqualTo (n :: Nat) Source #

A Predicate ensuring that the value is equal to the specified type-level number n.

Instances

(Eq x, Num x, KnownNat n) => Predicate (EqualTo n) x Source # 

Methods

validate :: Monad m => EqualTo n -> x -> RefineT m () Source #

data NotEqualTo (n :: Nat) Source #

A Predicate ensuring that the value is not equal to the specified type-level number n.

Instances

(Eq x, Num x, KnownNat n) => Predicate (NotEqualTo n) x Source # 

Methods

validate :: Monad m => NotEqualTo n -> x -> RefineT m () Source #

type Positive = GreaterThan 0 Source #

A Predicate ensuring that the value is greater than zero.

type NonPositive = To 0 Source #

A Predicate ensuring that the value is less than or equal to zero.

type Negative = LessThan 0 Source #

A Predicate ensuring that the value is less than zero.

type NonNegative = From 0 Source #

A Predicate ensuring that the value is greater than or equal to zero.

type ZeroToOne = FromTo 0 1 Source #

An inclusive range of values from zero to one.

type NonZero = NotEqualTo 0 Source #

A Predicate ensuring that the value is not equal to zero.

Foldable predicates

data SizeLessThan (n :: Nat) Source #

A Predicate ensuring that the Foldable has a length which is less than the specified type-level number.

Instances

(Foldable t, KnownNat n) => Predicate (SizeLessThan n) (t a) Source # 

Methods

validate :: Monad m => SizeLessThan n -> t a -> RefineT m () Source #

data SizeGreaterThan (n :: Nat) Source #

A Predicate ensuring that the Foldable has a length which is greater than the specified type-level number.

Instances

(Foldable t, KnownNat n) => Predicate (SizeGreaterThan n) (t a) Source # 

Methods

validate :: Monad m => SizeGreaterThan n -> t a -> RefineT m () Source #

data SizeEqualTo (n :: Nat) Source #

A Predicate ensuring that the Foldable has a length which is equal to the specified type-level number.

Instances

(Foldable t, KnownNat n) => Predicate (SizeEqualTo n) (t a) Source # 

Methods

validate :: Monad m => SizeEqualTo n -> t a -> RefineT m () Source #

type NonEmpty = SizeGreaterThan 0 Source #

A Predicate ensuring that the Foldable is non-empty.

IsList predicates

data Ascending Source #

A Predicate ensuring that the IsList contains elements in a strictly ascending order.

Instances

(IsList t, Ord (Item t)) => Predicate Ascending t Source # 

Methods

validate :: Monad m => Ascending -> t -> RefineT m () Source #

data Descending Source #

A Predicate ensuring that the IsList contains elements in a strictly descending order.

Instances

(IsList t, Ord (Item t)) => Predicate Descending t Source # 

Methods

validate :: Monad m => Descending -> t -> RefineT m () Source #

Weakening

class Weaken from to where Source #

A typeclass containing "safe" conversions between refined predicates where the target is weaker than the source: that is, all values that satisfy the first predicate will be guarunteed to satisy the second.

Take care: writing an instance declaration for your custom predicates is the same as an assertion that weaken is safe to use:

instance Weaken Pred1 Pred2

For most of the instances, explicit type annotations for the result value's type might be required.

Methods

weaken :: Refined from x -> Refined to x Source #

Instances

(<=) n m => Weaken (To n) (To m) Source # 

Methods

weaken :: Refined (To n) x -> Refined (To m) x Source #

(<=) m n => Weaken (From n) (From m) Source # 

Methods

weaken :: Refined (From n) x -> Refined (From m) x Source #

(<=) m n => Weaken (GreaterThan n) (From m) Source # 

Methods

weaken :: Refined (GreaterThan n) x -> Refined (From m) x Source #

(<=) m n => Weaken (GreaterThan n) (GreaterThan m) Source # 
(<=) n m => Weaken (LessThan n) (To m) Source # 

Methods

weaken :: Refined (LessThan n) x -> Refined (To m) x Source #

(<=) n m => Weaken (LessThan n) (LessThan m) Source # 

Methods

weaken :: Refined (LessThan n) x -> Refined (LessThan m) x Source #

(<=) m q => Weaken (FromTo n m) (To q) Source # 

Methods

weaken :: Refined (FromTo n m) x -> Refined (To q) x Source #

(<=) p n => Weaken (FromTo n m) (From p) Source # 

Methods

weaken :: Refined (FromTo n m) x -> Refined (From p) x Source #

((<=) p n, (<=) m q) => Weaken (FromTo n m) (FromTo p q) Source # 

Methods

weaken :: Refined (FromTo n m) x -> Refined (FromTo p q) x Source #

andLeft :: Refined (And l r) x -> Refined l x Source #

This function helps type inference. It is equivalent to the following:

instance Weaken (And l r) l

andRight :: Refined (And l r) x -> Refined r x Source #

This function helps type inference. It is equivalent to the following:

instance Weaken (And l r) r

leftOr :: Refined l x -> Refined (Or l r) x Source #

This function helps type inference. It is equivalent to the following:

instance Weaken l (Or l r)

rightOr :: Refined r x -> Refined (Or l r) x Source #

This function helps type inference. It is equivalent to the following:

instance Weaken r (Or l r)

Error handling

RefineException

data RefineException Source #

An exception encoding the way in which a Predicate failed.

Constructors

RefineNotException !TypeRep

A RefineException for failures involving the Not predicate.

RefineAndException !TypeRep !(These RefineException RefineException)

A RefineException for failures involving the And predicate.

RefineOrException !TypeRep !RefineException !RefineException

A RefineException for failures involving the Or predicate.

RefineOtherException !TypeRep !(Doc Void)

A RefineException for failures involving all other predicates.

Instances

Show RefineException Source # 
Generic RefineException Source # 
Exception RefineException Source #

Encode a RefineException for use with Control.Exception.

Pretty RefineException Source #

Pretty-print a RefineException.

Monad m => MonadError RefineException (RefineT m) Source # 
type Rep RefineException Source # 
type Rep RefineException = D1 * (MetaData "RefineException" "Refined" "refined-0.2.3.0-KLbSrGjAhi9IIdx1DlXFVr" False) ((:+:) * ((:+:) * (C1 * (MetaCons "RefineNotException" PrefixI True) (S1 * (MetaSel (Just Symbol "_RefineException_typeRep") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 * TypeRep))) (C1 * (MetaCons "RefineAndException" PrefixI True) ((:*:) * (S1 * (MetaSel (Just Symbol "_RefineException_typeRep") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 * TypeRep)) (S1 * (MetaSel (Just Symbol "_RefineException_andChild") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 * (These RefineException RefineException)))))) ((:+:) * (C1 * (MetaCons "RefineOrException" PrefixI True) ((:*:) * (S1 * (MetaSel (Just Symbol "_RefineException_typeRep") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 * TypeRep)) ((:*:) * (S1 * (MetaSel (Just Symbol "_RefineException_orLChild") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 * RefineException)) (S1 * (MetaSel (Just Symbol "_RefineException_orRChild") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 * RefineException))))) (C1 * (MetaCons "RefineOtherException" PrefixI True) ((:*:) * (S1 * (MetaSel (Just Symbol "_RefineException_typeRep") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 * TypeRep)) (S1 * (MetaSel (Just Symbol "_RefineException_message") NoSourceUnpackedness SourceStrict DecidedStrict) (Rec0 * (Doc Void)))))))

RefineT and RefineM

data RefineT m a Source #

A monad transformer that adds RefineExceptions to other monads.

The pure and return functions yield computations that produce the given value, while >>= sequences two subcomputations, exiting on the first RefineException.

Instances

MonadTrans RefineT Source # 

Methods

lift :: Monad m => m a -> RefineT m a #

Monad m => MonadError RefineException (RefineT m) Source # 
Monad m => Monad (RefineT m) Source # 

Methods

(>>=) :: RefineT m a -> (a -> RefineT m b) -> RefineT m b #

(>>) :: RefineT m a -> RefineT m b -> RefineT m b #

return :: a -> RefineT m a #

fail :: String -> RefineT m a #

Functor m => Functor (RefineT m) Source # 

Methods

fmap :: (a -> b) -> RefineT m a -> RefineT m b #

(<$) :: a -> RefineT m b -> RefineT m a #

MonadFix m => MonadFix (RefineT m) Source # 

Methods

mfix :: (a -> RefineT m a) -> RefineT m a #

Monad m => Applicative (RefineT m) Source # 

Methods

pure :: a -> RefineT m a #

(<*>) :: RefineT m (a -> b) -> RefineT m a -> RefineT m b #

liftA2 :: (a -> b -> c) -> RefineT m a -> RefineT m b -> RefineT m c #

(*>) :: RefineT m a -> RefineT m b -> RefineT m b #

(<*) :: RefineT m a -> RefineT m b -> RefineT m a #

Generic1 * (RefineT m) Source # 

Associated Types

type Rep1 (RefineT m) (f :: RefineT m -> *) :: k -> * #

Methods

from1 :: f a -> Rep1 (RefineT m) f a #

to1 :: Rep1 (RefineT m) f a -> f a #

Generic (RefineT m a) Source # 

Associated Types

type Rep (RefineT m a) :: * -> * #

Methods

from :: RefineT m a -> Rep (RefineT m a) x #

to :: Rep (RefineT m a) x -> RefineT m a #

type Rep1 * (RefineT m) Source # 
type Rep1 * (RefineT m) = D1 * (MetaData "RefineT" "Refined" "refined-0.2.3.0-KLbSrGjAhi9IIdx1DlXFVr" True) (C1 * (MetaCons "RefineT" PrefixI False) (S1 * (MetaSel (Nothing Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec1 * (ExceptT RefineException m))))
type Rep (RefineT m a) Source # 
type Rep (RefineT m a) = D1 * (MetaData "RefineT" "Refined" "refined-0.2.3.0-KLbSrGjAhi9IIdx1DlXFVr" True) (C1 * (MetaCons "RefineT" PrefixI False) (S1 * (MetaSel (Nothing Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 * (ExceptT RefineException m a))))

runRefineT :: RefineT m a -> m (Either RefineException a) Source #

The inverse of RefineT.

mapRefineT :: (m (Either RefineException a) -> n (Either RefineException b)) -> RefineT m a -> RefineT n b Source #

Map the unwrapped computation using the given function.

runRefineT (mapRefineT f m) = f (runRefineT m)

type RefineM a = RefineT Identity a Source #

RefineM a is equivalent to RefineT Identity a for any type a.

refineM :: Either RefineException a -> RefineM a Source #

Constructs a computation in the RefineM monad. (The inverse of runRefineM).

runRefineM :: RefineM a -> Either RefineException a Source #

Run a monadic action of type RefineM a, yielding an Either RefineException a.

This is just defined as runIdentity . runRefineT.

throwRefine :: Monad m => RefineException -> RefineT m a Source #

One can use throwRefine inside of a monadic context to begin processing a RefineException.

catchRefine :: Monad m => RefineT m a -> (RefineException -> RefineT m a) -> RefineT m a Source #

A handler function to handle previous RefineExceptions and return to normal execution. A common idiom is:

 do { action1; action2; action3 } `catchRefine' handler

where the action functions can call throwRefine. Note that handler and the do-block must have the same return type.

throwRefineOtherException Source #

Arguments

:: Monad m 
=> TypeRep

The TypeRep of the Predicate. This can usually be given by using typeOf.

-> Doc Void

A Doc Void encoding a custom error message to be pretty-printed.

-> RefineT m a 

A handler for a RefineException.

throwRefineOtherException is useful for defining what behaviour validate should have in the event of a predicate failure.