dep-t-advice-0.1.0.0: Giving good advice to functions in a DepT environment.
Safe HaskellNone
LanguageHaskell2010

Control.Monad.Dep.Advice

Description

This package provices the Advice datatype, along for functions for creating, manipulating, composing and applying values of that type.

Advices represent generic transformations on DepT-effectful functions of any number of arguments.

>>> :{
   foo0 :: DepT NilEnv IO (Sum Int)
   foo0 = pure (Sum 5)
   foo1 :: Bool -> DepT NilEnv IO (Sum Int)
   foo1 _ = foo0
   foo2 :: Char -> Bool -> DepT NilEnv IO (Sum Int)
   foo2 _ = foo1
:}

They work for DepT-actions of zero arguments:

>>> advise (printArgs @Top stdout "foo0") foo0 `runDepT` NilEnv
foo0:

Sum {getSum = 5}

And for functions of one or more arguments, provided they end on a DepT-action:

>>> advise (printArgs @Top stdout "foo1") foo1 False `runDepT` NilEnv
foo1: False

Sum {getSum = 5}
>>> advise (printArgs @Top stdout "foo2") foo2 'd' False `runDepT` NilEnv
foo2: 'd' False

Sum {getSum = 5}

Advices can also tweak the result value of functions:

>>> advise (returnMempty @Top @Top2) foo2 'd' False `runDepT` NilEnv
Sum {getSum = 0}

And they can be combined using Advice's Monoid instance before being applied (although that might require harmonizing their constraint parameters):

>>> advise (printArgs stdout "foo2" <> returnMempty) foo2 'd' False `runDepT` NilEnv
foo2: 'd' False

Sum {getSum = 0}
Synopsis

The Advice type

data Advice ca cem cr Source #

A generic transformation of a DepT-effectful function of any number of arguments, provided the function satisfies certain constraints on the arguments, the environment type constructor and base monad, and the return type.

It is parameterized by three constraints:

  • ca of kind Type -> Constraint, the constraint required of each argument (usually something like Show).
  • cem of kind ((Type -> Type) -> Type) -> (Type -> Type) -> Constraint, a two-place constraint required of the environment type constructor / base monad combination. Note that the environment type constructor remains unapplied. That is, for a given cem, cem NilEnv IO kind-checks but cem (NilEnv IO) IO doesn't. See also Ensure.
  • cr of kind Type -> Constraint, the constraint required of the return type.

We can define Advices that work with concrete types by using MustBe in the case of ca and cr, and MustBe2 in the case of cem.

Advices that don't care about a particular constraint can leave it polymorphic, and this facilitates composition, but the constraint must be given some concrete value (Top in the case of ca and cr, Top2 in the case of cem) through type application at the moment of calling advise.

See Control.Monad.Dep.Advice.Basic for examples.

Instances

Instances details
Semigroup (Advice ca cem cr) Source #

Aspects compose "sequentially" when tweaking the arguments, and "concentrically" when tweaking the final DepT action.

The first Advice is the "outer" one. It tweaks the function arguments first, and wraps around the execution of the second, "inner" Advice.

Instance details

Defined in Control.Monad.Dep.Advice

Methods

(<>) :: Advice ca cem cr -> Advice ca cem cr -> Advice ca cem cr #

sconcat :: NonEmpty (Advice ca cem cr) -> Advice ca cem cr #

stimes :: Integral b => b -> Advice ca cem cr -> Advice ca cem cr #

Monoid (Advice ca cem cr) Source # 
Instance details

Defined in Control.Monad.Dep.Advice

Methods

mempty :: Advice ca cem cr #

mappend :: Advice ca cem cr -> Advice ca cem cr -> Advice ca cem cr #

mconcat :: [Advice ca cem cr] -> Advice ca cem cr #

Creating Advice values

makeAdvice Source #

Arguments

:: forall u ca cem cr. (forall as e m. (All ca as, cem e m, Monad m) => NP I as -> DepT e m (u, NP I as))

The function that tweaks the arguments.

-> (forall e m r. (cem e m, Monad m, cr r) => u -> DepT e m r -> DepT e m r)

The function that tweaks the execution.

-> Advice ca cem cr 

The most general (and complex) way of constructing Advices.

Advices work in two phases. First, the arguments of the transformed function are collected into an n-ary product NP, and passed to the first argument of makeAdvice, which produces a (possibly transformed) product of arguments, along with some summary value of type u. Use () as the summary value if you don't care about it.

In the second phase, the monadic action produced by the function once all arguments have been given is transformed using the second argument of makeAdvice. This second argument also receives the summary value of type u calculated earlier.

>>> :{
 doesNothing :: forall ca cem cr. Advice ca cem cr
 doesNothing = makeAdvice @() (\args -> pure (pure args)) (\() action -> action)
:}

IMPORTANT! When invoking makeAdvice, you must always give the type of the existential u through a type application. Otherwise you'll get weird "u is untouchable" errors.

makeArgsAdvice Source #

Arguments

:: forall ca cem cr. (forall as e m. (All ca as, cem e m, Monad m) => NP I as -> DepT e m (NP I as))

The function that tweaks the arguments.

-> Advice ca cem cr 

Create an advice which only tweaks and/or analyzes the function arguments.

Notice that there's no u parameter, unlike with makeAdvice.

>>> :{
 doesNothing :: forall ca cem cr. Advice ca cem cr
 doesNothing = makeArgsAdvice pure
:}

makeExecutionAdvice Source #

Arguments

:: forall ca cem cr. (forall e m r. (cem e m, Monad m, cr r) => DepT e m r -> DepT e m r)

The function that tweaks the execution.

-> Advice ca cem cr 

Create an advice which only tweaks the execution of the final monadic action.

Notice that there's no u parameter, unlike with makeAdvice.

>>> :{
 doesNothing :: forall ca cem cr. Advice ca cem cr
 doesNothing = makeExecutionAdvice id
:}

Applying Advices

advise Source #

Arguments

:: forall ca cem cr as e m r advisee. (Multicurryable as e m r advisee, All ca as, cem e m, Monad m, cr r) 
=> Advice ca cem cr

The advice to apply.

-> advisee

A function to be adviced.

-> advisee 

Apply an Advice to some compatible function. The function must have its effects in DepT, and satisfy the constraints required by the Advice.

IMPORTANT! If the ca, cem or cr constraints of the supplied Advice remain polymorphic, they must be given types by means of type applications:

>>> :{
 foo :: Int -> DepT NilEnv IO String
 foo _ = pure "foo"
 advisedFoo1 = advise (returnMempty @Top @Top2) foo
 advisedFoo2 = advise @Top @Top2 returnMempty foo
 advisedFoo3 = advise (printArgs @Top stdout "args: ") foo
 advisedFoo4 = advise @_ @_ @Top (printArgs stdout "args: ") foo
:}

Constraint helpers

Some class synonyms to help create the constraints that parameterize the Advice type.

This library also re-exports the Top, And and All helpers from "sop-core":

  • Top is the "always satisfied" constraint, useful when whe don't want to require anything specific in ca or cr (cem requires Top2).
  • And combines constraints for ca or cr (cem requires And2).
  • All says that some constraint is satisfied by all the components of an NP product. In this library, it's used to stipulate constraints on the arguments of advised functions.

class c (e (DepT e m)) (DepT e m) => Ensure c e m Source #

Ensure is a helper for lifting typeclass definitions of the form:

>>> :{
 type HasLogger :: Type -> (Type -> Type) -> Constraint
 class HasLogger em m | em -> m where
   logger :: em -> String -> m ()
:}

To work as the cem constraint, like this:

>>> type FooAdvice = Advice Top (Ensure HasLogger) Top

Why is it necessary? Two-place HasX-style constraints receive the "fully applied" type of the record-of-functions. That is: NilEnv IO instead of simply NilEnv. This allows them to also work with monomorphic environments (like those in RIO) whose type isn't parameterized by any monad.

But the cem constraint works with the type constructor of the environment record, of kind (Type -> Type) -> Type, and not with the fully applied type of kind Type.

Instances

Instances details
c (e (DepT e m)) (DepT e m) => Ensure c e m Source # 
Instance details

Defined in Control.Monad.Dep.Advice

class Top2 e m Source #

A two-place constraint which requires nothing of the environment and the base monad.

Useful as the cem type application argument of advise and restrictEnv.

For similar behavior with the ar and cr type arguments of advise and restrictEnv, use Top from "sop-core".

>>> type UselessAdvice = Advice Top Top2 Top

Instances

Instances details
Top2 e m Source # 
Instance details

Defined in Control.Monad.Dep.Advice

class (f e m, g e m) => And2 f g e m infixl 7 Source #

Combines two two-place constraints on the environment / monad pair.

For example, an advice which requires both Ensure HasLogger and Ensure HasRepository might use this.

Useful to build the cem type application argument of advise and restrictEnv.

For similar behavior with the ar and cr type arguments of advise and restrictEnv, use And from "sop-core".

Instances

Instances details
(f e m, g e m) => And2 f g e m Source # 
Instance details

Defined in Control.Monad.Dep.Advice

class c m => MonadConstraint c e m Source #

Require a constraint only on the base monad, for example a base moonad with MonadIO.

Useful to build cem type application argument of advise and restrictEnv.

>>> type FooAdvice = Advice Top (MonadConstraint MonadIO) Top
>>> type FooAdvice = Advice Top (MonadConstraint (MonadReader Int)) Top

Instances

Instances details
c m => MonadConstraint c e m Source # 
Instance details

Defined in Control.Monad.Dep.Advice

class c e => EnvConstraint c e m Source #

Require a constraint only on the unapplied environment type constructor, which has kind (Type -> Type) -> Type.

Can be used to build cem type application argument of advise and restrictEnv.

Most of the time this is not what you want. One exception is when pinning the environment with a MustBe equality constraint, while leaving the base monad free:

>>> type FooAdvice = Advice Top (EnvConstraint (MustBe NilEnv)) Top

If what you want is to lift a two-parameter HasX-style typeclass to cem, use Ensure instead.

Instances

Instances details
c e => EnvConstraint c e m Source # 
Instance details

Defined in Control.Monad.Dep.Advice

class x ~ y => MustBe x y Source #

A class synonym for (~), the type equality constraint.

Poly-kinded, so it can be applied both to type constructors (like monads) and to concrete types.

It this library it will be used partially applied:

>>> type FooAdvice = Advice Top (MonadConstraint (MustBe IO)) Top
>>> type FooAdvice = Advice Top Top2 (MustBe String)

Instances

Instances details
x ~ y => MustBe (x :: k) (y :: k) Source # 
Instance details

Defined in Control.Monad.Dep.Advice

class (e' ~ e, m' ~ m) => MustBe2 e' m' e m Source #

Pins both the environment type constructor and the base monad. Sometimes we don't want to advise functions in some generic environment, but in a concrete environment having access to all the fields, and in a concrete base monad.

Useful to build the cem type application argument of advise and restricEnv.

For similar behavior with the ar and cr type arguments of advise and restrictEnv, use MustBe.

It this library it will be used partially applied:

>>> type FooAdvice = Advice Top (MustBe2 NilEnv IO) Top

Instances

Instances details
(e' ~ e, m' ~ m) => MustBe2 e' m' e m Source # 
Instance details

Defined in Control.Monad.Dep.Advice

Combining Advices by harmonizing their constraints

Advice values can be composed using the Monoid instance, but only if the have the same constraint parameters. It's unfortunate that—unlike with normal functions—Advice constaints aren't automatically "collected" during composition.

We need to harmonize the constraints on each Advice by turning them into the combination of all constraints. The functions in this section help with that.

These functions take as parameter evidence of entailment between constraints, using the type (:-) from the "constraints" package. But how to construct such evidence? By using the Sub and the Dict constructors, with either an explicit type signature:

>>> :{
returnMempty' :: Advice ca cem (Monoid `And` Show)
returnMempty' = restrictResult (Sub Dict) returnMempty
:}

or with a type application to the restriction function:

>>> :{
returnMempty'' :: Advice ca cem (Monoid `And` Show)
returnMempty'' = restrictResult @(Monoid `And` Show) (Sub Dict) returnMempty
:}

Another example:

>>> :{
 type HasLogger :: Type -> (Type -> Type) -> Constraint
 class HasLogger em m | em -> m where
   logger :: em -> String -> m ()
 doLogging :: Advice Show (Ensure HasLogger) cr
 doLogging = undefined
 type EnsureLoggerAndWriter :: ((Type -> Type) -> Type) -> (Type -> Type) -> Constraint
 type EnsureLoggerAndWriter = Ensure HasLogger `And2` MonadConstraint MonadIO
 doLogging':: Advice Show EnsureLoggerAndWriter cr
 doLogging'= restrictEnv (Sub Dict) doLogging
 doLogging'' = restrictEnv @EnsureLoggerAndWriter (Sub Dict) doLogging
:}

restrictArgs Source #

Arguments

:: forall more less cem cr. (forall r. more r :- less r)

Evidence that one constraint implies the other.

-> Advice less cem cr

Advice with less restrictive constraint on the args.

-> Advice more cem cr

Advice with more restrictive constraint on the args.

Makes the constraint on the arguments more restrictive.

restrictEnv Source #

Arguments

:: forall more ca less cr. (forall e m. more e m :- less e m)

Evidence that one constraint implies the other.

-> Advice ca less cr

Advice with less restrictive constraint on the environment and base monad.

-> Advice ca more cr

Advice with more restrictive constraint on the environment and base monad.

Makes the constraint on the environment / monad more restrictive.

restrictResult Source #

Arguments

:: forall more ca cem less. (forall r. more r :- less r)

Evidence that one constraint implies the other.

-> Advice ca cem less

Advice with less restrictive constraint on the result.

-> Advice ca cem more

Advice with more restrictive constraint on the result.

Makes the constraint on the result more restrictive.

Invocation helpers

There functions are helpers for running DepT computations, beyond what runDepT provides.

They aren't directly related to Advices, but they require some of the same machinery, and that's why they are here.

runFinalDepT Source #

Arguments

:: forall as e m r curried. Multicurryable as e m r curried 
=> m (e (DepT e m))

action that gets hold of the environment

-> curried

function to invoke with effects in DepT

-> BaseMonadAtTheTip as e m r curried

a new function with effects in the base monad

Given a base monad m action that gets hold of the DepT environment, run the DepT transformer at the tip of a curried function.

>>> :{
 foo :: Int -> Int -> Int -> DepT NilEnv IO ()
 foo _ _ _ = pure ()
:}
>>> runFinalDepT (pure NilEnv) foo 1 2 3 :: IO ()

runFromEnv Source #

Arguments

:: forall as e m r curried. (Multicurryable as e m r curried, Monad m) 
=> m (e (DepT e m))

action that gets hold of the environment

-> (e (DepT e m) -> curried)

gets a function from the environment with effects in DepT

-> BaseMonadAtTheTip as e m r curried

a new function with effects in the base monad

Given a base monad m action that gets hold of the DepT environment, and a function capable of extracting a curried function from the environment, run the DepT transformer at the tip of the resulting curried function.

Why put the environment behind the m action? Well, since getting to the end of the curried function takes some work, it's a good idea to have some flexibility once we arrive there. For example, the environment could be stored in a Data.IORef and change in response to events, perhaps with advices being added or removed.

>>> :{
  type MutableEnv :: (Type -> Type) -> Type
  data MutableEnv m = MutableEnv { _foo :: Int -> m (Sum Int) }
  :}
>>> :{
  do envRef <- newIORef (MutableEnv (pure . Sum))
     let foo' = runFromEnv (readIORef envRef) _foo
     do r <- foo' 7
        print r
     modifyIORef envRef (\e -> e { _foo = advise @Top @Top2 returnMempty (_foo e) })
     do r <- foo' 7
        print r
:}
Sum {getSum = 7}
Sum {getSum = 0}

"sop-core" re-exports

Some useful definitions re-exported the from "sop-core" package.

NP is an n-ary product used to represent the arguments of advised functions.

I is an identity functor. The arguments processed by an Advice come wrapped in it.

cfoldMap_NP is useful to construct homogeneous lists out of the NP product, for example:

>>> cfoldMap_NP (Proxy @Show) (\(I a) -> [show a]) (I False :* I (1::Int) :* Nil)
["False","1"]

class Top (x :: k) #

A constraint that can always be satisfied.

Since: sop-core-0.2

Instances

Instances details
Top (x :: k) 
Instance details

Defined in Data.SOP.Constraint

class (f x, g x) => And (f :: k -> Constraint) (g :: k -> Constraint) (x :: k) infixl 7 #

Pairing of constraints.

Since: sop-core-0.2

Instances

Instances details
(f x, g x) => And (f :: k -> Constraint) (g :: k -> Constraint) (x :: k) 
Instance details

Defined in Data.SOP.Constraint

class (AllF c xs, SListI xs) => All (c :: k -> Constraint) (xs :: [k]) #

Require a constraint for every element of a list.

If you have a datatype that is indexed over a type-level list, then you can use All to indicate that all elements of that type-level list must satisfy a given constraint.

Example: The constraint

All Eq '[ Int, Bool, Char ]

is equivalent to the constraint

(Eq Int, Eq Bool, Eq Char)

Example: A type signature such as

f :: All Eq xs => NP I xs -> ...

means that f can assume that all elements of the n-ary product satisfy Eq.

Note on superclasses: ghc cannot deduce superclasses from All constraints. You might expect the following to compile

class (Eq a) => MyClass a

foo :: (All Eq xs) => NP f xs -> z
foo = [..]

bar :: (All MyClass xs) => NP f xs -> x
bar = foo

but it will fail with an error saying that it was unable to deduce the class constraint AllF Eq xs (or similar) in the definition of bar. In cases like this you can use Dict from Data.SOP.Dict to prove conversions between constraints. See this answer on SO for more details.

Minimal complete definition

cpara_SList

Instances

Instances details
All (c :: k -> Constraint) ('[] :: [k]) 
Instance details

Defined in Data.SOP.Constraint

Methods

cpara_SList :: proxy c -> r '[] -> (forall (y :: k0) (ys :: [k0]). (c y, All c ys) => r ys -> r (y ': ys)) -> r '[] #

(c x, All c xs) => All (c :: a -> Constraint) (x ': xs :: [a]) 
Instance details

Defined in Data.SOP.Constraint

Methods

cpara_SList :: proxy c -> r '[] -> (forall (y :: k) (ys :: [k]). (c y, All c ys) => r ys -> r (y ': ys)) -> r (x ': xs) #

data NP (a :: k -> Type) (b :: [k]) where #

An n-ary product.

The product is parameterized by a type constructor f and indexed by a type-level list xs. The length of the list determines the number of elements in the product, and if the i-th element of the list is of type x, then the i-th element of the product is of type f x.

The constructor names are chosen to resemble the names of the list constructors.

Two common instantiations of f are the identity functor I and the constant functor K. For I, the product becomes a heterogeneous list, where the type-level list describes the types of its components. For K a, the product becomes a homogeneous list, where the contents of the type-level list are ignored, but its length still specifies the number of elements.

In the context of the SOP approach to generic programming, an n-ary product describes the structure of the arguments of a single data constructor.

Examples:

I 'x'    :* I True  :* Nil  ::  NP I       '[ Char, Bool ]
K 0      :* K 1     :* Nil  ::  NP (K Int) '[ Char, Bool ]
Just 'x' :* Nothing :* Nil  ::  NP Maybe   '[ Char, Bool ]

Constructors

Nil :: forall k (a :: k -> Type). NP a ('[] :: [k]) 
(:*) :: forall k (a :: k -> Type) (x :: k) (xs :: [k]). a x -> NP a xs -> NP a (x ': xs) infixr 5 

Instances

Instances details
HTrans (NP :: (k1 -> Type) -> [k1] -> Type) (NP :: (k2 -> Type) -> [k2] -> Type) 
Instance details

Defined in Data.SOP.NP

Methods

htrans :: forall c (xs :: l1) (ys :: l2) proxy f g. AllZipN (Prod NP) c xs ys => proxy c -> (forall (x :: k10) (y :: k20). c x y => f x -> g y) -> NP f xs -> NP g ys #

hcoerce :: forall (f :: k10 -> Type) (g :: k20 -> Type) (xs :: l1) (ys :: l2). AllZipN (Prod NP) (LiftedCoercible f g) xs ys => NP f xs -> NP g ys #

HPure (NP :: (k -> Type) -> [k] -> Type) 
Instance details

Defined in Data.SOP.NP

Methods

hpure :: forall (xs :: l) f. SListIN NP xs => (forall (a :: k0). f a) -> NP f xs #

hcpure :: forall c (xs :: l) proxy f. AllN NP c xs => proxy c -> (forall (a :: k0). c a => f a) -> NP f xs #

HAp (NP :: (k -> Type) -> [k] -> Type) 
Instance details

Defined in Data.SOP.NP

Methods

hap :: forall (f :: k0 -> Type) (g :: k0 -> Type) (xs :: l). Prod NP (f -.-> g) xs -> NP f xs -> NP g xs #

HCollapse (NP :: (k -> Type) -> [k] -> Type) 
Instance details

Defined in Data.SOP.NP

Methods

hcollapse :: forall (xs :: l) a. SListIN NP xs => NP (K a) xs -> CollapseTo NP a #

HTraverse_ (NP :: (k -> Type) -> [k] -> Type) 
Instance details

Defined in Data.SOP.NP

Methods

hctraverse_ :: forall c (xs :: l) g proxy f. (AllN NP c xs, Applicative g) => proxy c -> (forall (a :: k0). c a => f a -> g ()) -> NP f xs -> g () #

htraverse_ :: forall (xs :: l) g f. (SListIN NP xs, Applicative g) => (forall (a :: k0). f a -> g ()) -> NP f xs -> g () #

HSequence (NP :: (k -> Type) -> [k] -> Type) 
Instance details

Defined in Data.SOP.NP

Methods

hsequence' :: forall (xs :: l) f (g :: k0 -> Type). (SListIN NP xs, Applicative f) => NP (f :.: g) xs -> f (NP g xs) #

hctraverse' :: forall c (xs :: l) g proxy f f'. (AllN NP c xs, Applicative g) => proxy c -> (forall (a :: k0). c a => f a -> g (f' a)) -> NP f xs -> g (NP f' xs) #

htraverse' :: forall (xs :: l) g f f'. (SListIN NP xs, Applicative g) => (forall (a :: k0). f a -> g (f' a)) -> NP f xs -> g (NP f' xs) #

All (Compose Eq f) xs => Eq (NP f xs) 
Instance details

Defined in Data.SOP.NP

Methods

(==) :: NP f xs -> NP f xs -> Bool #

(/=) :: NP f xs -> NP f xs -> Bool #

(All (Compose Eq f) xs, All (Compose Ord f) xs) => Ord (NP f xs) 
Instance details

Defined in Data.SOP.NP

Methods

compare :: NP f xs -> NP f xs -> Ordering #

(<) :: NP f xs -> NP f xs -> Bool #

(<=) :: NP f xs -> NP f xs -> Bool #

(>) :: NP f xs -> NP f xs -> Bool #

(>=) :: NP f xs -> NP f xs -> Bool #

max :: NP f xs -> NP f xs -> NP f xs #

min :: NP f xs -> NP f xs -> NP f xs #

All (Compose Show f) xs => Show (NP f xs) 
Instance details

Defined in Data.SOP.NP

Methods

showsPrec :: Int -> NP f xs -> ShowS #

show :: NP f xs -> String #

showList :: [NP f xs] -> ShowS #

All (Compose Semigroup f) xs => Semigroup (NP f xs)

Since: sop-core-0.4.0.0

Instance details

Defined in Data.SOP.NP

Methods

(<>) :: NP f xs -> NP f xs -> NP f xs #

sconcat :: NonEmpty (NP f xs) -> NP f xs #

stimes :: Integral b => b -> NP f xs -> NP f xs #

(All (Compose Monoid f) xs, All (Compose Semigroup f) xs) => Monoid (NP f xs)

Since: sop-core-0.4.0.0

Instance details

Defined in Data.SOP.NP

Methods

mempty :: NP f xs #

mappend :: NP f xs -> NP f xs -> NP f xs #

mconcat :: [NP f xs] -> NP f xs #

All (Compose NFData f) xs => NFData (NP f xs)

Since: sop-core-0.2.5.0

Instance details

Defined in Data.SOP.NP

Methods

rnf :: NP f xs -> () #

type AllZipN (NP :: (k -> Type) -> [k] -> Type) (c :: a -> b -> Constraint) 
Instance details

Defined in Data.SOP.NP

type AllZipN (NP :: (k -> Type) -> [k] -> Type) (c :: a -> b -> Constraint) = AllZip c
type Same (NP :: (k1 -> Type) -> [k1] -> Type) 
Instance details

Defined in Data.SOP.NP

type Same (NP :: (k1 -> Type) -> [k1] -> Type) = NP :: (k2 -> Type) -> [k2] -> Type
type Prod (NP :: (k -> Type) -> [k] -> Type) 
Instance details

Defined in Data.SOP.NP

type Prod (NP :: (k -> Type) -> [k] -> Type) = NP :: (k -> Type) -> [k] -> Type
type UnProd (NP :: (k -> Type) -> [k] -> Type) 
Instance details

Defined in Data.SOP.NS

type UnProd (NP :: (k -> Type) -> [k] -> Type) = NS :: (k -> Type) -> [k] -> Type
type SListIN (NP :: (k -> Type) -> [k] -> Type) 
Instance details

Defined in Data.SOP.NP

type SListIN (NP :: (k -> Type) -> [k] -> Type) = SListI :: [k] -> Constraint
type CollapseTo (NP :: (k -> Type) -> [k] -> Type) a 
Instance details

Defined in Data.SOP.NP

type CollapseTo (NP :: (k -> Type) -> [k] -> Type) a = [a]
type AllN (NP :: (k -> Type) -> [k] -> Type) (c :: k -> Constraint) 
Instance details

Defined in Data.SOP.NP

type AllN (NP :: (k -> Type) -> [k] -> Type) (c :: k -> Constraint) = All c

newtype I a #

The identity type functor.

Like Identity, but with a shorter name.

Constructors

I a 

Instances

Instances details
Monad I 
Instance details

Defined in Data.SOP.BasicFunctors

Methods

(>>=) :: I a -> (a -> I b) -> I b #

(>>) :: I a -> I b -> I b #

return :: a -> I a #

Functor I 
Instance details

Defined in Data.SOP.BasicFunctors

Methods

fmap :: (a -> b) -> I a -> I b #

(<$) :: a -> I b -> I a #

Applicative I 
Instance details

Defined in Data.SOP.BasicFunctors

Methods

pure :: a -> I a #

(<*>) :: I (a -> b) -> I a -> I b #

liftA2 :: (a -> b -> c) -> I a -> I b -> I c #

(*>) :: I a -> I b -> I b #

(<*) :: I a -> I b -> I a #

Foldable I 
Instance details

Defined in Data.SOP.BasicFunctors

Methods

fold :: Monoid m => I m -> m #

foldMap :: Monoid m => (a -> m) -> I a -> m #

foldMap' :: Monoid m => (a -> m) -> I a -> m #

foldr :: (a -> b -> b) -> b -> I a -> b #

foldr' :: (a -> b -> b) -> b -> I a -> b #

foldl :: (b -> a -> b) -> b -> I a -> b #

foldl' :: (b -> a -> b) -> b -> I a -> b #

foldr1 :: (a -> a -> a) -> I a -> a #

foldl1 :: (a -> a -> a) -> I a -> a #

toList :: I a -> [a] #

null :: I a -> Bool #

length :: I a -> Int #

elem :: Eq a => a -> I a -> Bool #

maximum :: Ord a => I a -> a #

minimum :: Ord a => I a -> a #

sum :: Num a => I a -> a #

product :: Num a => I a -> a #

Traversable I 
Instance details

Defined in Data.SOP.BasicFunctors

Methods

traverse :: Applicative f => (a -> f b) -> I a -> f (I b) #

sequenceA :: Applicative f => I (f a) -> f (I a) #

mapM :: Monad m => (a -> m b) -> I a -> m (I b) #

sequence :: Monad m => I (m a) -> m (I a) #

Eq1 I

Since: sop-core-0.2.4.0

Instance details

Defined in Data.SOP.BasicFunctors

Methods

liftEq :: (a -> b -> Bool) -> I a -> I b -> Bool #

Ord1 I

Since: sop-core-0.2.4.0

Instance details

Defined in Data.SOP.BasicFunctors

Methods

liftCompare :: (a -> b -> Ordering) -> I a -> I b -> Ordering #

Read1 I

Since: sop-core-0.2.4.0

Instance details

Defined in Data.SOP.BasicFunctors

Methods

liftReadsPrec :: (Int -> ReadS a) -> ReadS [a] -> Int -> ReadS (I a) #

liftReadList :: (Int -> ReadS a) -> ReadS [a] -> ReadS [I a] #

liftReadPrec :: ReadPrec a -> ReadPrec [a] -> ReadPrec (I a) #

liftReadListPrec :: ReadPrec a -> ReadPrec [a] -> ReadPrec [I a] #

Show1 I

Since: sop-core-0.2.4.0

Instance details

Defined in Data.SOP.BasicFunctors

Methods

liftShowsPrec :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> Int -> I a -> ShowS #

liftShowList :: (Int -> a -> ShowS) -> ([a] -> ShowS) -> [I a] -> ShowS #

NFData1 I

Since: sop-core-0.2.5.0

Instance details

Defined in Data.SOP.BasicFunctors

Methods

liftRnf :: (a -> ()) -> I a -> () #

Eq a => Eq (I a) 
Instance details

Defined in Data.SOP.BasicFunctors

Methods

(==) :: I a -> I a -> Bool #

(/=) :: I a -> I a -> Bool #

Ord a => Ord (I a) 
Instance details

Defined in Data.SOP.BasicFunctors

Methods

compare :: I a -> I a -> Ordering #

(<) :: I a -> I a -> Bool #

(<=) :: I a -> I a -> Bool #

(>) :: I a -> I a -> Bool #

(>=) :: I a -> I a -> Bool #

max :: I a -> I a -> I a #

min :: I a -> I a -> I a #

Read a => Read (I a) 
Instance details

Defined in Data.SOP.BasicFunctors

Methods

readsPrec :: Int -> ReadS (I a) #

readList :: ReadS [I a] #

readPrec :: ReadPrec (I a) #

readListPrec :: ReadPrec [I a] #

Show a => Show (I a) 
Instance details

Defined in Data.SOP.BasicFunctors

Methods

showsPrec :: Int -> I a -> ShowS #

show :: I a -> String #

showList :: [I a] -> ShowS #

Generic (I a) 
Instance details

Defined in Data.SOP.BasicFunctors

Associated Types

type Rep (I a) :: Type -> Type #

Methods

from :: I a -> Rep (I a) x #

to :: Rep (I a) x -> I a #

Semigroup a => Semigroup (I a)

Since: sop-core-0.4.0.0

Instance details

Defined in Data.SOP.BasicFunctors

Methods

(<>) :: I a -> I a -> I a #

sconcat :: NonEmpty (I a) -> I a #

stimes :: Integral b => b -> I a -> I a #

Monoid a => Monoid (I a)

Since: sop-core-0.4.0.0

Instance details

Defined in Data.SOP.BasicFunctors

Methods

mempty :: I a #

mappend :: I a -> I a -> I a #

mconcat :: [I a] -> I a #

NFData a => NFData (I a)

Since: sop-core-0.2.5.0

Instance details

Defined in Data.SOP.BasicFunctors

Methods

rnf :: I a -> () #

type Rep (I a) 
Instance details

Defined in Data.SOP.BasicFunctors

type Rep (I a) = D1 ('MetaData "I" "Data.SOP.BasicFunctors" "sop-core-0.5.0.1-LSgc1wfRk3m3wHkiLjj5ug" 'True) (C1 ('MetaCons "I" 'PrefixI 'False) (S1 ('MetaSel ('Nothing :: Maybe Symbol) 'NoSourceUnpackedness 'NoSourceStrictness 'DecidedLazy) (Rec0 a)))

cfoldMap_NP :: forall k c (xs :: [k]) m proxy f. (All c xs, Monoid m) => proxy c -> (forall (a :: k). c a => f a -> m) -> NP f xs -> m #

Specialization of hcfoldMap.

Since: sop-core-0.3.2.0

"constraints" re-exports

Some useful definitions re-exported the from "constraints" package.

Dict and (:-) are GADTs used to capture and transform constraints. Used in the restrictArgs, restrictEnv and restrictResult functions.

newtype a :- b infixr 9 #

This is the type of entailment.

a :- b is read as a "entails" b.

With this we can actually build a category for Constraint resolution.

e.g.

Because Eq a is a superclass of Ord a, we can show that Ord a entails Eq a.

Because instance Ord a => Ord [a] exists, we can show that Ord a entails Ord [a] as well.

This relationship is captured in the :- entailment type here.

Since p :- p and entailment composes, :- forms the arrows of a Category of constraints. However, Category only became sufficiently general to support this instance in GHC 7.8, so prior to 7.8 this instance is unavailable.

But due to the coherence of instance resolution in Haskell, this Category has some very interesting properties. Notably, in the absence of IncoherentInstances, this category is "thin", which is to say that between any two objects (constraints) there is at most one distinguishable arrow.

This means that for instance, even though there are two ways to derive Ord a :- Eq [a], the answers from these two paths _must_ by construction be equal. This is a property that Haskell offers that is pretty much unique in the space of languages with things they call "type classes".

What are the two ways?

Well, we can go from Ord a :- Eq a via the superclass relationship, and then from Eq a :- Eq [a] via the instance, or we can go from Ord a :- Ord [a] via the instance then from Ord [a] :- Eq [a] through the superclass relationship and this diagram by definition must "commute".

Diagrammatically,

                   Ord a
               ins /     \ cls
                  v       v
            Ord [a]     Eq a
               cls \     / ins
                    v   v
                   Eq [a]

This safety net ensures that pretty much anything you can write with this library is sensible and can't break any assumptions on the behalf of library authors.

Constructors

Sub (a => Dict b) 

Instances

Instances details
Category (:-)

Possible since GHC 7.8, when Category was made polykinded.

Instance details

Defined in Data.Constraint

Methods

id :: forall (a :: k). a :- a #

(.) :: forall (b :: k) (c :: k) (a :: k). (b :- c) -> (a :- b) -> a :- c #

() :=> (Eq (a :- b)) 
Instance details

Defined in Data.Constraint

Methods

ins :: () :- Eq (a :- b) #

() :=> (Ord (a :- b)) 
Instance details

Defined in Data.Constraint

Methods

ins :: () :- Ord (a :- b) #

() :=> (Show (a :- b)) 
Instance details

Defined in Data.Constraint

Methods

ins :: () :- Show (a :- b) #

a => HasDict b (a :- b) 
Instance details

Defined in Data.Constraint

Methods

evidence :: (a :- b) -> Dict b #

Eq (a :- b)

Assumes IncoherentInstances doesn't exist.

Instance details

Defined in Data.Constraint

Methods

(==) :: (a :- b) -> (a :- b) -> Bool #

(/=) :: (a :- b) -> (a :- b) -> Bool #

(Typeable p, Typeable q, p, q) => Data (p :- q) 
Instance details

Defined in Data.Constraint

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> (p :- q) -> c (p :- q) #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (p :- q) #

toConstr :: (p :- q) -> Constr #

dataTypeOf :: (p :- q) -> DataType #

dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (p :- q)) #

dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (p :- q)) #

gmapT :: (forall b. Data b => b -> b) -> (p :- q) -> p :- q #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> (p :- q) -> r #

gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> (p :- q) -> r #

gmapQ :: (forall d. Data d => d -> u) -> (p :- q) -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> (p :- q) -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> (p :- q) -> m (p :- q) #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> (p :- q) -> m (p :- q) #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> (p :- q) -> m (p :- q) #

Ord (a :- b)

Assumes IncoherentInstances doesn't exist.

Instance details

Defined in Data.Constraint

Methods

compare :: (a :- b) -> (a :- b) -> Ordering #

(<) :: (a :- b) -> (a :- b) -> Bool #

(<=) :: (a :- b) -> (a :- b) -> Bool #

(>) :: (a :- b) -> (a :- b) -> Bool #

(>=) :: (a :- b) -> (a :- b) -> Bool #

max :: (a :- b) -> (a :- b) -> a :- b #

min :: (a :- b) -> (a :- b) -> a :- b #

Show (a :- b) 
Instance details

Defined in Data.Constraint

Methods

showsPrec :: Int -> (a :- b) -> ShowS #

show :: (a :- b) -> String #

showList :: [a :- b] -> ShowS #

a => NFData (a :- b) 
Instance details

Defined in Data.Constraint

Methods

rnf :: (a :- b) -> () #

data Dict a where #

Values of type Dict p capture a dictionary for a constraint of type p.

e.g.

Dict :: Dict (Eq Int)

captures a dictionary that proves we have an:

instance Eq 'Int

Pattern matching on the Dict constructor will bring this instance into scope.

Constructors

Dict :: forall a. a => Dict a 

Instances

Instances details
HasDict a (Dict a) 
Instance details

Defined in Data.Constraint

Methods

evidence :: Dict a -> Dict a #

a :=> (Read (Dict a)) 
Instance details

Defined in Data.Constraint

Methods

ins :: a :- Read (Dict a) #

a :=> (Monoid (Dict a)) 
Instance details

Defined in Data.Constraint

Methods

ins :: a :- Monoid (Dict a) #

a :=> (Enum (Dict a)) 
Instance details

Defined in Data.Constraint

Methods

ins :: a :- Enum (Dict a) #

a :=> (Bounded (Dict a)) 
Instance details

Defined in Data.Constraint

Methods

ins :: a :- Bounded (Dict a) #

() :=> (Eq (Dict a)) 
Instance details

Defined in Data.Constraint

Methods

ins :: () :- Eq (Dict a) #

() :=> (Ord (Dict a)) 
Instance details

Defined in Data.Constraint

Methods

ins :: () :- Ord (Dict a) #

() :=> (Show (Dict a)) 
Instance details

Defined in Data.Constraint

Methods

ins :: () :- Show (Dict a) #

() :=> (Semigroup (Dict a)) 
Instance details

Defined in Data.Constraint

Methods

ins :: () :- Semigroup (Dict a) #

a => Bounded (Dict a) 
Instance details

Defined in Data.Constraint

Methods

minBound :: Dict a #

maxBound :: Dict a #

a => Enum (Dict a) 
Instance details

Defined in Data.Constraint

Methods

succ :: Dict a -> Dict a #

pred :: Dict a -> Dict a #

toEnum :: Int -> Dict a #

fromEnum :: Dict a -> Int #

enumFrom :: Dict a -> [Dict a] #

enumFromThen :: Dict a -> Dict a -> [Dict a] #

enumFromTo :: Dict a -> Dict a -> [Dict a] #

enumFromThenTo :: Dict a -> Dict a -> Dict a -> [Dict a] #

Eq (Dict a) 
Instance details

Defined in Data.Constraint

Methods

(==) :: Dict a -> Dict a -> Bool #

(/=) :: Dict a -> Dict a -> Bool #

(Typeable p, p) => Data (Dict p) 
Instance details

Defined in Data.Constraint

Methods

gfoldl :: (forall d b. Data d => c (d -> b) -> d -> c b) -> (forall g. g -> c g) -> Dict p -> c (Dict p) #

gunfold :: (forall b r. Data b => c (b -> r) -> c r) -> (forall r. r -> c r) -> Constr -> c (Dict p) #

toConstr :: Dict p -> Constr #

dataTypeOf :: Dict p -> DataType #

dataCast1 :: Typeable t => (forall d. Data d => c (t d)) -> Maybe (c (Dict p)) #

dataCast2 :: Typeable t => (forall d e. (Data d, Data e) => c (t d e)) -> Maybe (c (Dict p)) #

gmapT :: (forall b. Data b => b -> b) -> Dict p -> Dict p #

gmapQl :: (r -> r' -> r) -> r -> (forall d. Data d => d -> r') -> Dict p -> r #

gmapQr :: forall r r'. (r' -> r -> r) -> r -> (forall d. Data d => d -> r') -> Dict p -> r #

gmapQ :: (forall d. Data d => d -> u) -> Dict p -> [u] #

gmapQi :: Int -> (forall d. Data d => d -> u) -> Dict p -> u #

gmapM :: Monad m => (forall d. Data d => d -> m d) -> Dict p -> m (Dict p) #

gmapMp :: MonadPlus m => (forall d. Data d => d -> m d) -> Dict p -> m (Dict p) #

gmapMo :: MonadPlus m => (forall d. Data d => d -> m d) -> Dict p -> m (Dict p) #

Ord (Dict a) 
Instance details

Defined in Data.Constraint

Methods

compare :: Dict a -> Dict a -> Ordering #

(<) :: Dict a -> Dict a -> Bool #

(<=) :: Dict a -> Dict a -> Bool #

(>) :: Dict a -> Dict a -> Bool #

(>=) :: Dict a -> Dict a -> Bool #

max :: Dict a -> Dict a -> Dict a #

min :: Dict a -> Dict a -> Dict a #

a => Read (Dict a) 
Instance details

Defined in Data.Constraint

Show (Dict a) 
Instance details

Defined in Data.Constraint

Methods

showsPrec :: Int -> Dict a -> ShowS #

show :: Dict a -> String #

showList :: [Dict a] -> ShowS #

Semigroup (Dict a) 
Instance details

Defined in Data.Constraint

Methods

(<>) :: Dict a -> Dict a -> Dict a #

sconcat :: NonEmpty (Dict a) -> Dict a #

stimes :: Integral b => b -> Dict a -> Dict a #

a => Monoid (Dict a) 
Instance details

Defined in Data.Constraint

Methods

mempty :: Dict a #

mappend :: Dict a -> Dict a -> Dict a #

mconcat :: [Dict a] -> Dict a #

NFData (Dict c) 
Instance details

Defined in Data.Constraint

Methods

rnf :: Dict c -> () #