| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
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/
This module only provides safe constructions of Refined
values, safe meaning that the refinement predicate holds,
and the construction of the Refined value is total.
If you can manually prove that the refinement predicate holds, or you do not necessarily care about this definition of safety, use the module Refined.Unsafe.
Synopsis
- data Refined p x
- refine :: Predicate p x => x -> Either RefineException (Refined p x)
- refine_ :: forall p x. Predicate p x => x -> Either RefineException x
- refineThrow :: (Predicate p x, MonadThrow m) => x -> m (Refined p x)
- refineFail :: (Predicate p x, MonadFail m) => x -> m (Refined p x)
- refineError :: (Predicate p x, MonadError RefineException m) => x -> m (Refined p x)
- refineTH :: (Predicate p x, Lift x) => x -> Q (TExp (Refined p x))
- refineTH_ :: forall p x. (Predicate p x, Lift x) => x -> Q (TExp x)
- unrefine :: Refined p x -> x
- class Typeable p => Predicate p x where
- reifyPredicate :: forall p a. Predicate p a => a -> Bool
- data Not p = Not
- data And l r = And
- type (&&) = And
- data Or l r = Or
- type (||) = Or
- data IdPred = IdPred
- data LessThan (n :: Nat) = LessThan
- data GreaterThan (n :: Nat) = GreaterThan
- data From (n :: Nat) = From
- data To (n :: Nat) = To
- data FromTo (mn :: Nat) (mx :: Nat) = FromTo
- data NegativeFromTo (n :: Nat) (m :: Nat) = NegativeFromTo
- data EqualTo (n :: Nat) = EqualTo
- data NotEqualTo (n :: Nat) = NotEqualTo
- data Odd = Odd
- data Even = Even
- data DivisibleBy (n :: Nat) = DivisibleBy
- type Positive = GreaterThan 0
- type NonPositive = To 0
- type Negative = LessThan 0
- type NonNegative = From 0
- type ZeroToOne = FromTo 0 1
- type NonZero = NotEqualTo 0
- data SizeLessThan (n :: Nat) = SizeLessThan
- data SizeGreaterThan (n :: Nat) = SizeGreaterThan
- data SizeEqualTo (n :: Nat) = SizeEqualTo
- type NonEmpty = SizeGreaterThan 0
- data Ascending = Ascending
- data Descending = Descending
- class Weaken from to where
- andLeft :: Refined (And l r) x -> Refined l x
- andRight :: Refined (And l r) x -> Refined r x
- leftOr :: Refined l x -> Refined (Or l r) x
- rightOr :: Refined r x -> Refined (Or l r) x
- strengthen :: forall p p' x. (Predicate p x, Predicate p' x) => Refined p x -> Either RefineException (Refined (p && p') x)
- strengthenM :: forall p p' x m. (Predicate p x, Predicate p' x, Monad m) => Refined p x -> RefineT m (Refined (p && p') x)
- data RefineException
- displayRefineException :: RefineException -> Doc ann
- data RefineT m a
- runRefineT :: RefineT m a -> m (Either RefineException a)
- exceptRefine :: Monad m => Either RefineException a -> RefineT m a
- mapRefineT :: (m (Either RefineException a) -> n (Either RefineException b)) -> RefineT m a -> RefineT n b
- type RefineM a = RefineT Identity a
- refineM :: Either RefineException a -> RefineM a
- runRefineM :: RefineM a -> Either RefineException a
- throwRefine :: Monad m => RefineException -> RefineT m a
- catchRefine :: Monad m => RefineT m a -> (RefineException -> RefineT m a) -> RefineT m a
- throwRefineOtherException :: Monad m => TypeRep -> Doc Void -> RefineT m a
- pretty :: Pretty a => a -> Doc ann
Refined
A refinement type, which wraps a value of type x,
ensuring that it satisfies a type-level predicate p.
Instances
| Foldable (Refined p) Source # | |
Defined in Refined.Internal 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] # 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 # | |
| Eq x => Eq (Refined p x) Source # | |
| Ord x => Ord (Refined p x) Source # | |
Defined in Refined.Internal | |
| (Read x, Predicate p x) => Read (Refined p x) Source # | This instance makes sure to check the refinement. |
| Show x => Show (Refined p x) Source # | |
| Lift x => Lift (Refined p x) Source # | |
| (Arbitrary a, Typeable a, Typeable p, Predicate p a) => Arbitrary (Refined p a) Source # | |
| (ToJSON a, Predicate p a) => ToJSON (Refined p a) Source # | |
Defined in Refined.Orphan.Aeson | |
| (FromJSON a, Predicate p a) => FromJSON (Refined p a) Source # | |
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.
refine_ :: forall p x. Predicate p x => x -> Either RefineException x Source #
Like refine, but discards the refinement.
This _can_ be useful when you only need to validate
that some value at runtime satisfies some predicate.
See also reifyPredicate.
refineThrow :: (Predicate p x, MonadThrow m) => x -> m (Refined p x) Source #
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.
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 IntIf 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.
It may be useful to use this function with the `th-lift-instances` package at https://hackage.haskell.org/package/th-lift-instances/
refineTH_ :: forall p x. (Predicate p x, Lift x) => x -> Q (TExp x) Source #
Like refineTH, but immediately unrefines the value.
This is useful when some value need only be refined
at compile-time.
Consumption
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.
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
reifyPredicate :: forall p a. Predicate p a => a -> Bool Source #
Reify a Predicate by turning it into a value-level predicate.
Logical predicates
The negation of a predicate.
>>>isRight (refine @(Not NonEmpty) @[Int] [])True
>>>isLeft (refine @(Not NonEmpty) @[Int] [1,2])True
Constructors
| Not |
The conjunction of two predicates.
>>>isLeft (refine @(And Positive Negative) @Int 3)True
>>>isRight (refine @(And Positive Odd) @Int 203)True
Constructors
| And |
The disjunction of two predicates.
>>>isRight (refine @(Or Even Odd) @Int 3)True
>>>isRight (refine @(Or (LessThan 3) (GreaterThan 3)) @Int 2)True
Constructors
| Or |
Identity predicate
A predicate which is satisfied for all types.
Arguments passed to in validate
are not evaluated.validate IdPred x
>>>isRight (refine @IdPred @Int undefined)True
>>>isLeft (refine @IdPred @Int undefined)False
Constructors
| IdPred |
Numeric predicates
data LessThan (n :: Nat) Source #
A Predicate ensuring that the value is less than the
specified type-level number.
>>>isRight (refine @(LessThan 12) @Int 11)True
>>>isLeft (refine @(LessThan 12) @Int 12)True
Constructors
| LessThan |
data GreaterThan (n :: Nat) Source #
A Predicate ensuring that the value is greater than the
specified type-level number.
>>>isRight (refine @(GreaterThan 65) @Int 67)True
>>>isLeft (refine @(GreaterThan 65) @Int 65)True
Constructors
| GreaterThan |
Instances
| Generic (GreaterThan n) Source # | |
Defined in Refined.Internal Associated Types type Rep (GreaterThan n) :: Type -> Type # Methods from :: GreaterThan n -> Rep (GreaterThan n) x # to :: Rep (GreaterThan n) x -> GreaterThan n # | |
| (Ord x, Num x, KnownNat n) => Predicate (GreaterThan n) x Source # | |
Defined in Refined.Internal | |
| m <= n => Weaken (GreaterThan n) (From m) Source # | |
Defined in Refined.Internal | |
| m <= n => Weaken (GreaterThan n) (GreaterThan m) Source # | |
Defined in Refined.Internal Methods weaken :: Refined (GreaterThan n) x -> Refined (GreaterThan m) x Source # | |
| type Rep (GreaterThan n) Source # | |
A Predicate ensuring that the value is greater than or equal to the
specified type-level number.
>>>isRight (refine @(From 9) @Int 10)True
>>>isRight (refine @(From 10) @Int 10)True
>>>isLeft (refine @(From 11) @Int 10)True
Constructors
| From |
A Predicate ensuring that the value is less than or equal to the
specified type-level number.
>>>isRight (refine @(To 23) @Int 17)True
>>>isLeft (refine @(To 17) @Int 23)True
Constructors
| To |
data FromTo (mn :: Nat) (mx :: Nat) Source #
A Predicate ensuring that the value is within an inclusive range.
>>>isRight (refine @(FromTo 0 16) @Int 13)True
>>>isRight (refine @(FromTo 13 15) @Int 13)True
>>>isRight (refine @(FromTo 13 15) @Int 15)True
>>>isLeft (refine @(FromTo 13 15) @Int 12)True
Constructors
| FromTo |
Instances
| Generic (FromTo mn mx) Source # | |
| (Ord x, Num x, KnownNat mn, KnownNat mx, mn <= mx) => Predicate (FromTo mn mx) x Source # | |
| m <= q => Weaken (FromTo n m) (To q) Source # | |
| p <= n => Weaken (FromTo n m) (From p) Source # | |
| (p <= n, m <= q) => Weaken (FromTo n m) (FromTo p q) Source # | |
| type Rep (FromTo mn mx) Source # | |
data NegativeFromTo (n :: Nat) (m :: Nat) Source #
A Predicate ensuring that the value is greater or equal than a negative
number specified as a type-level (positive) number n and less than a
type-level (positive) number m.
>>>isRight (refine @(NegativeFromTo 5 12) @Int (-3))True
>>>isLeft (refine @(NegativeFromTo 4 3) @Int (-5))True
Constructors
| NegativeFromTo |
Instances
| Generic (NegativeFromTo n m) Source # | |
Defined in Refined.Internal Associated Types type Rep (NegativeFromTo n m) :: Type -> Type # Methods from :: NegativeFromTo n m -> Rep (NegativeFromTo n m) x # to :: Rep (NegativeFromTo n m) x -> NegativeFromTo n m # | |
| (Ord x, Num x, KnownNat n, KnownNat m) => Predicate (NegativeFromTo n m) x Source # | |
Defined in Refined.Internal | |
| type Rep (NegativeFromTo n m) Source # | |
data EqualTo (n :: Nat) Source #
A Predicate ensuring that the value is equal to the specified
type-level number n.
>>>isRight (refine @(EqualTo 5) @Int 5)True
>>>isLeft (refine @(EqualTo 6) @Int 5)True
Constructors
| EqualTo |
data NotEqualTo (n :: Nat) Source #
A Predicate ensuring that the value is not equal to the specified
type-level number n.
>>>isRight (refine @(NotEqualTo 6) @Int 5)True
>>>isLeft (refine @(NotEqualTo 5) @Int 5)True
Constructors
| NotEqualTo |
Instances
| Generic (NotEqualTo n) Source # | |
Defined in Refined.Internal Associated Types type Rep (NotEqualTo n) :: Type -> Type # | |
| (Eq x, Num x, KnownNat n) => Predicate (NotEqualTo n) x Source # | |
Defined in Refined.Internal | |
| type Rep (NotEqualTo n) Source # | |
A Predicate ensuring that the value is odd.
>>>isRight (refine @Odd @Int 33)True
>>>isLeft (refine @Odd @Int 32)True
Constructors
| Odd |
A Predicate ensuring that the value is even.
>>>isRight (refine @Even @Int 32)True
>>>isLeft (refine @Even @Int 33)True
Constructors
| Even |
data DivisibleBy (n :: Nat) Source #
A Predicate ensuring that the value is divisible by n.
>>>isRight (refine @(DivisibleBy 3) @Int 12)True
>>>isLeft (refine @(DivisibleBy 2) @Int 37)True
Constructors
| DivisibleBy |
Instances
| Generic (DivisibleBy n) Source # | |
Defined in Refined.Internal Associated Types type Rep (DivisibleBy n) :: Type -> Type # Methods from :: DivisibleBy n -> Rep (DivisibleBy n) x # to :: Rep (DivisibleBy n) x -> DivisibleBy n # | |
| (Integral x, KnownNat n) => Predicate (DivisibleBy n) x Source # | |
Defined in Refined.Internal | |
| type Rep (DivisibleBy n) 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 NonNegative = From 0 Source #
A Predicate ensuring that the value is greater than or equal to zero.
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.
>>>isRight (refine @(SizeLessThan 4) @[Int] [1,2,3])True
>>>isLeft (refine @(SizeLessThan 5) @[Int] [1,2,3,4,5])True
Constructors
| SizeLessThan |
Instances
| Generic (SizeLessThan n) Source # | |
Defined in Refined.Internal Associated Types type Rep (SizeLessThan n) :: Type -> Type # Methods from :: SizeLessThan n -> Rep (SizeLessThan n) x # to :: Rep (SizeLessThan n) x -> SizeLessThan n # | |
| (Foldable t, KnownNat n) => Predicate (SizeLessThan n) (t a) Source # | |
Defined in Refined.Internal | |
| type Rep (SizeLessThan n) Source # | |
data SizeGreaterThan (n :: Nat) Source #
A Predicate ensuring that the Foldable has a length
which is greater than the specified type-level number.
>>>isLeft (refine @(SizeGreaterThan 3) @[Int] [1,2,3])True
>>>isRight (refine @(SizeGreaterThan 3) @[Int] [1,2,3,4,5])True
Constructors
| SizeGreaterThan |
Instances
| Generic (SizeGreaterThan n) Source # | |
Defined in Refined.Internal Associated Types type Rep (SizeGreaterThan n) :: Type -> Type # Methods from :: SizeGreaterThan n -> Rep (SizeGreaterThan n) x # to :: Rep (SizeGreaterThan n) x -> SizeGreaterThan n # | |
| (Foldable t, KnownNat n) => Predicate (SizeGreaterThan n) (t a) Source # | |
Defined in Refined.Internal | |
| type Rep (SizeGreaterThan n) Source # | |
data SizeEqualTo (n :: Nat) Source #
A Predicate ensuring that the Foldable has a length
which is equal to the specified type-level number.
>>>isRight (refine @(SizeEqualTo 4) @[Int] [1,2,3,4])True
>>>isLeft (refine @(SizeEqualTo 35) @[Int] [1,2,3,4])True
Constructors
| SizeEqualTo |
Instances
| Generic (SizeEqualTo n) Source # | |
Defined in Refined.Internal Associated Types type Rep (SizeEqualTo n) :: Type -> Type # Methods from :: SizeEqualTo n -> Rep (SizeEqualTo n) x # to :: Rep (SizeEqualTo n) x -> SizeEqualTo n # | |
| (Foldable t, KnownNat n) => Predicate (SizeEqualTo n) (t a) Source # | |
Defined in Refined.Internal | |
| type Rep (SizeEqualTo n) Source # | |
IsList predicates
A Predicate ensuring that the Foldable contains elements
in a strictly ascending order.
>>>isRight (refine @Ascending @[Int] [5, 8, 13, 21, 34])True
>>>isLeft (refine @Ascending @[Int] [34, 21, 13, 8, 5])True
Constructors
| Ascending |
data Descending Source #
A Predicate ensuring that the Foldable contains elements
in a strictly descending order.
>>>isRight (refine @Descending @[Int] [34, 21, 13, 8, 5])True
>>>isLeft (refine @Descending @[Int] [5, 8, 13, 21, 34])True
Constructors
| Descending |
Instances
| Generic Descending Source # | |
Defined in Refined.Internal Associated Types type Rep Descending :: Type -> Type # | |
| (Foldable t, Ord a) => Predicate Descending (t a) Source # | |
Defined in Refined.Internal | |
| type Rep Descending 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.
Minimal complete definition
Nothing
Instances
| n <= m => Weaken (To n) (To m) Source # | |
| m <= n => Weaken (From n) (From m) Source # | |
| m <= n => Weaken (GreaterThan n) (From m) Source # | |
Defined in Refined.Internal | |
| m <= n => Weaken (GreaterThan n) (GreaterThan m) Source # | |
Defined in Refined.Internal Methods weaken :: Refined (GreaterThan n) x -> Refined (GreaterThan m) x Source # | |
| n <= m => Weaken (LessThan n) (To m) Source # | |
| n <= m => Weaken (LessThan n) (LessThan m) Source # | |
| m <= q => Weaken (FromTo n m) (To q) Source # | |
| p <= n => Weaken (FromTo n m) (From p) Source # | |
| (p <= n, m <= q) => Weaken (FromTo n m) (FromTo p q) 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)
Strengthening
strengthen :: forall p p' x. (Predicate p x, Predicate p' x) => Refined p x -> Either RefineException (Refined (p && p') x) Source #
Strengthen a refinement by composing it with another.
strengthenM :: forall p p' x m. (Predicate p x, Predicate p' x, Monad m) => Refined p x -> RefineT m (Refined (p && p') x) Source #
Strengthen a refinement by composing it with another
inside of the RefineT monad.
Error handling
RefineException
data RefineException Source #
An exception encoding the way in which a Predicate failed.
Constructors
| RefineNotException !TypeRep | A |
| RefineAndException !TypeRep !(These RefineException RefineException) | A |
| RefineOrException !TypeRep !RefineException !RefineException | A |
| RefineOtherException !TypeRep !(Doc Void) | A |
Instances
displayRefineException :: RefineException -> Doc ann Source #
Display a RefineException as a Doc ann
RefineT and RefineM
A monad transformer that adds s to other monads.RefineException
The and pure functions yield computations that produce
the given value, while return sequences two subcomputations, exiting
on the first >>=.RefineException
Instances
| MonadTrans RefineT Source # | |
Defined in Refined.Internal | |
| Monad m => MonadError RefineException (RefineT m) Source # | |
Defined in Refined.Internal Methods throwError :: RefineException -> RefineT m a # catchError :: RefineT m a -> (RefineException -> RefineT m a) -> RefineT m a # | |
| Monad m => Monad (RefineT m) Source # | |
| Functor m => Functor (RefineT m) Source # | |
| MonadFix m => MonadFix (RefineT m) Source # | |
Defined in Refined.Internal | |
| Monad m => Applicative (RefineT m) Source # | |
| Generic1 (RefineT m :: Type -> Type) Source # | |
| Generic (RefineT m a) Source # | |
| type Rep1 (RefineT m :: Type -> Type) Source # | |
Defined in Refined.Internal | |
| type Rep (RefineT m a) Source # | |
Defined in Refined.Internal type Rep (RefineT m a) = D1 (MetaData "RefineT" "Refined.Internal" "refined-0.4.4-7xXnhN9HJ7XByi1PQY08Xe" True) (C1 (MetaCons "RefineT" PrefixI False) (S1 (MetaSel (Nothing :: Maybe Symbol) NoSourceUnpackedness NoSourceStrictness DecidedLazy) (Rec0 (ExceptT RefineException m a)))) | |
runRefineT :: RefineT m a -> m (Either RefineException a) Source #
The inverse of .RefineT
exceptRefine :: Monad m => Either RefineException a -> RefineT m a Source #
Constructor for computations in the movie.
(The inverse of RefineTrunRefineT).
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(mapRefineTf m) = f (runRefineTm)
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 ,
yielding an RefineM a.Either RefineException a
This is just defined as .runIdentity . runRefineT
throwRefine :: Monad m => RefineException -> RefineT m a Source #
One can use inside of a monadic
context to begin processing a throwRefine.RefineException
catchRefine :: Monad m => RefineT m a -> (RefineException -> RefineT m a) -> RefineT m a Source #
A handler function to handle previous s
and return to normal execution. A common idiom is:RefineException
do { action1; action2; action3 } `catchRefine' handlerwhere the action functions can call . Note that
handler and the do-block must have the same return type.throwRefine
throwRefineOtherException Source #
Arguments
| :: Monad m | |
| => TypeRep | The |
| -> Doc Void | A |
| -> 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.