License | BSD-3 |
---|---|
Maintainer | autotaker@gmail.com |
Stability | experimental |
Safe Haskell | None |
Language | Haskell2010 |
Synopsis
- mockup :: Method method => Mock method -> method
- thenReturn :: (Behave x, Method (MethodOf x)) => Condition x -> Ret (MethodOf x) -> x
- thenAction :: (Behave x, Method (MethodOf x)) => Condition x -> Base (MethodOf x) (Ret (MethodOf x)) -> x
- thenMethod :: Behave x => Condition x -> MethodOf x -> x
- throwNoStubWithShow :: Method method => (Args method -> String) -> (Args method -> Bool) -> Mock method
- throwNoStub :: (Method method, Show (AsTuple (Args method)), TupleLike (Args method)) => Matcher (Args method) -> Mock method
- data DynamicShow
- data Dynamic
- castMethod :: (ToDyn (Args method) (Args method'), FromDyn (Ret method) (Ret method'), Method method, Method method', Base method ~ Base method') => method -> method'
- dynArg :: (Typeable a, DynamicLike b) => Matcher a -> Matcher b
- class FromDyn a b where
- fromDyn :: a -> b
- class ToDyn a b where
- toDyn :: b -> a
- class Typeable (a :: k)
- data Monitor args ret
- data Event args ret
- watchBy :: (Method method, MonadUnliftIO (Base method)) => (Args method -> args) -> (Ret method -> ret) -> Monitor args ret -> method -> method
- watch :: (Method method, MonadUnliftIO (Base method)) => Monitor (Args method) (Ret method) -> method -> method
- withMonitor :: MonadIO m => (Monitor args ret -> m a) -> m (a, [Event args ret])
- withMonitor_ :: MonadIO m => (Monitor args ret -> m ()) -> m [Event args ret]
- call :: Matcher args -> Matcher (Event args ret)
- times :: Matcher Int -> Matcher (Event args ret) -> Matcher [Event args ret]
- newMonitor :: IO (Monitor args ret)
- listenEventLog :: MonadIO m => Monitor args ret -> m [Event args ret]
- protocol :: ProtocolM f a -> IO (ProtocolEnv f)
- data ProtocolM f a
- data ProtocolEnv f
- data CallId
- decl :: IsMethodName f m => Call f m -> ProtocolM f CallId
- whenArgs :: ArgsMatcher (Args m) => f m -> EachMatcher (Args m) -> CallArgs f m
- dependsOn :: Call f m -> [CallId] -> Call f m
- lookupMock :: forall f m. (IsMethodName f m, Show (AsTuple (Args m)), TupleLike (Args m), Method m, MonadIO (Base m)) => f m -> ProtocolEnv f -> m
- lookupMockWithShow :: forall f m. (IsMethodName f m, Method m, MonadIO (Base m)) => (Args m -> String) -> f m -> ProtocolEnv f -> m
- verify :: ProtocolEnv f -> IO ()
- type Matcher a = a -> Bool
- anything :: Matcher a
- when :: Matcher a -> Matcher a
- class TupleLike a where
- class TupleLike a => ArgsMatcher a where
- args :: EachMatcher a -> Matcher a
- args' :: TupleLike a => Matcher (AsTuple a) -> Matcher a
Documentation
This module provides DSLs for mocking methods and for validating method calls
Mocking monomorphic methods
Usage
fizzbuzz :: Int -> IO String fizzbuzz =mockup
$ dowhen
(args
(\x -> mod x 15 == 0)) `thenReturn
` "fizzbuzz"when
(args
(\x -> mod x 3 == 0)) `thenReturn
` "fizz"when
(args
(\x -> mod x 5 == 0)) `thenReturn
` "buzz"when
(args
(>=0)) `thenMethod
` (\x -> pure $ show x)throwNoStub
$when
anything
>>>
fizzbuzz 0
"fizzbuzz">>>
fizzbuzz 1
"1">>>
fizzbuzz 3
"fizz">>>
fizzbuzz 5
"buzz">>>
fizzbuzz (-1)
*** Exception: no stub found for argument: -1 CallStack (from HasCallStack): error, called at src/Test/Method/Mock.hs:98:9 in method-0.2.0.0-inplace:Test.Method.Mock"
References
mockup :: Method method => Mock method -> method Source #
generate a method from Mock DSL. Mock DSL consists of rules. On a call of generated method, the first rule matched the arguments is applied.
thenReturn :: (Behave x, Method (MethodOf x)) => Condition x -> Ret (MethodOf x) -> x Source #
Specify behavior that return a constant value for a call
thenAction :: (Behave x, Method (MethodOf x)) => Condition x -> Base (MethodOf x) (Ret (MethodOf x)) -> x Source #
Specify behavior that executes an action for a call
thenMethod :: Behave x => Condition x -> MethodOf x -> x Source #
Specify behavior from a pair of a condition and a method.
throwNoStubWithShow :: Method method => (Args method -> String) -> (Args method -> Bool) -> Mock method Source #
means the method raises runtime exception
if the arguments matches throwNoStubWithShow
fshow matchermatcher
. The argument tuple is converted to String
by
using fshow
function.
throwNoStub :: (Method method, Show (AsTuple (Args method)), TupleLike (Args method)) => Matcher (Args method) -> Mock method Source #
means the method raises a runtime exception
if the arguments matches throwNoStub
matchermatcher
. The argument tuple is converted to String
by
using show
function.
Mocking polymorphic methods
Usage
Often you want to mock polymorphic functions. For example, assume that we are testing the following method.
type QueryFunc = forall q r. (ToRow q, FromRow r) => Query -> q -> IO [r] service :: QueryFunc -> Day -> IO [Event] service query today = do events <- query "SELECT * FROM event WHERE date = ?" (Only today) pure events
Because QueryFunc
is a polymorphic function, it is impossible to mock directly with mockup
.
In order to mock QueryFunc
, first add Typeable
(and Show
) constraint(s) for each type variables.
type QueryFunc = forall q r. (ToRow q,Typeable
q,Show
q, FromRow r,Typeable
r,Show
r) => Query -> q -> IO [r]
Next, we mock dynamic version of QueryFunc
, where each type variable is replaced with DynamicShow
(or Dynamic
).
Finally, we obtain polymorphic method by casting
the dynamic version with castMethod
.
queryDyn :: Query ->DynamicShow
-> IO [DynamicShow
] queryDyn =mockup
$ ... queryMock :: QueryFunc queryMock =castMethod
queryDyn
Now you can write test for service
as follows.
spec :: Spec spec = do describe "service" $ do it "return events whose dates are equal to today" $ do let today = fromGregorian 2020 2 20 sql = "SELECT * FROM event WHERE date = ?" events = [Event 0, Event 1] queryDyn :: Query ->DynamicShow
-> IO [DynamicShow
] queryDyn = mockup $ when (args ((==sql),dynArg
(==today)))`thenReturn`
toDyn
events service (castMethod
queryDyn) today`shouldReturn`
events
data DynamicShow Source #
Dynamic value whose content is showable.
Using this type instead of Dynamic
is recommended because it gives better error messages.
Instances
Show DynamicShow Source # | |
Defined in Test.Method.Dynamic showsPrec :: Int -> DynamicShow -> ShowS # show :: DynamicShow -> String # showList :: [DynamicShow] -> ShowS # | |
DynamicLike DynamicShow Source # | |
Defined in Test.Method.Dynamic asDyn :: DynamicShow -> Dynamic Source # | |
(Typeable a, Show a) => ToDyn DynamicShow a Source # | |
Defined in Test.Method.Dynamic toDyn :: a -> DynamicShow Source # | |
(Typeable a, Show a) => FromDyn DynamicShow a Source # | |
Defined in Test.Method.Dynamic fromDyn :: DynamicShow -> a Source # |
A value of type Dynamic
is an object encapsulated together with its type.
A Dynamic
may only represent a monomorphic value; an attempt to
create a value of type Dynamic
from a polymorphically-typed
expression will result in an ambiguity error (see toDyn
).
Show
ing a value of type Dynamic
returns a pretty-printed representation
of the object's type; useful for debugging.
Instances
Show Dynamic | Since: base-2.1 |
Exception Dynamic | Since: base-4.0.0.0 |
Defined in Data.Dynamic toException :: Dynamic -> SomeException # fromException :: SomeException -> Maybe Dynamic # displayException :: Dynamic -> String # | |
DynamicLike Dynamic Source # | |
Typeable a => ToDyn Dynamic a Source # | |
Defined in Test.Method.Dynamic | |
Typeable a => FromDyn Dynamic a Source # | |
Defined in Test.Method.Dynamic |
castMethod :: (ToDyn (Args method) (Args method'), FromDyn (Ret method) (Ret method'), Method method, Method method', Base method ~ Base method') => method -> method' Source #
convert a dynamically-typed method to a polymorphic method.
fDyn :: String -> DynamicShow -> Dynamic -> IO [DynamicShow] fDyn = ... fPoly :: (Typeable a, Show a, Typeable b, Typeable c, Show c) => String -> a -> b -> IO [c] fPoly = castMethod fDyn
dynArg :: (Typeable a, DynamicLike b) => Matcher a -> Matcher b Source #
Convert given matcher to dynamic matcher. The dynamic matcher matches a dynamic value only if the value has the type of given matcher.
class FromDyn a b where Source #
FromDyn a b
provides a function to convert type a
to type b
,
where b
is a type whose dynamic type occurences are replaced by concrete types.
For example: FromDyn (Int, Dynamic, Maybe Dynamic) (Int, Bool, Maybe String)
Nothing
convert dynamic value to specified type. It thows runtime exception if the dynamic value does not have specified type.
Instances
FromDyn a a Source # | |
Defined in Test.Method.Dynamic | |
Typeable a => FromDyn Dynamic a Source # | |
Defined in Test.Method.Dynamic | |
(Typeable a, Show a) => FromDyn DynamicShow a Source # | |
Defined in Test.Method.Dynamic fromDyn :: DynamicShow -> a Source # | |
FromDyn a b => FromDyn [a] [b] Source # | |
Defined in Test.Method.Dynamic | |
FromDyn a b => FromDyn (Maybe a) (Maybe b) Source # | |
(ToDyn a a', FromDyn b b') => FromDyn (a -> b) (a' -> b') Source # | |
Defined in Test.Method.Dynamic | |
(FromDyn a a', FromDyn b b') => FromDyn (Either a b) (Either a' b') Source # | |
(FromDyn a a', FromDyn b b') => FromDyn (a, b) (a', b') Source # | |
Defined in Test.Method.Dynamic | |
(FromDyn a b, FromDyn c d) => FromDyn (a :* c) (b :* d) Source # | |
(FromDyn a a', FromDyn b b', FromDyn c c') => FromDyn (a, b, c) (a', b', c') Source # | |
Defined in Test.Method.Dynamic | |
(FromDyn a a', FromDyn b b', FromDyn c c', FromDyn d d') => FromDyn (a, b, c, d) (a', b', c', d') Source # | |
Defined in Test.Method.Dynamic | |
(FromDyn a a', FromDyn b b', FromDyn c c', FromDyn d d', FromDyn e e') => FromDyn (a, b, c, d, e) (a', b', c', d', e') Source # | |
Defined in Test.Method.Dynamic | |
(FromDyn a a', FromDyn b b', FromDyn c c', FromDyn d d', FromDyn e e', FromDyn f f') => FromDyn (a, b, c, d, e, f) (a', b', c', d', e', f') Source # | |
Defined in Test.Method.Dynamic | |
(FromDyn a a', FromDyn b b', FromDyn c c', FromDyn d d', FromDyn e e', FromDyn f f', FromDyn g g') => FromDyn (a, b, c, d, e, f, g) (a', b', c', d', e', f', g') Source # | |
Defined in Test.Method.Dynamic |
class ToDyn a b where Source #
ToDyn a b
provides a function to convert type b
to type a
, where
b
is a type whose dynamic type occurences are replaced by concrete types.
For example: ToDyn (Int, Dynamic, Maybe Dynamic) (Int, Bool, Maybe String)
Nothing
convert value of specified type to dynamic value
Instances
ToDyn a a Source # | |
Defined in Test.Method.Dynamic | |
Typeable a => ToDyn Dynamic a Source # | |
Defined in Test.Method.Dynamic | |
(Typeable a, Show a) => ToDyn DynamicShow a Source # | |
Defined in Test.Method.Dynamic toDyn :: a -> DynamicShow Source # | |
ToDyn a b => ToDyn [a] [b] Source # | |
Defined in Test.Method.Dynamic | |
ToDyn a b => ToDyn (Maybe a) (Maybe b) Source # | |
(FromDyn a a', ToDyn b b') => ToDyn (a -> b) (a' -> b') Source # | |
Defined in Test.Method.Dynamic | |
(ToDyn a a', ToDyn b b') => ToDyn (Either a b) (Either a' b') Source # | |
(ToDyn a a', ToDyn b b') => ToDyn (a, b) (a', b') Source # | |
Defined in Test.Method.Dynamic | |
(ToDyn a b, ToDyn c d) => ToDyn (a :* c) (b :* d) Source # | |
(ToDyn a a', ToDyn b b', ToDyn c c') => ToDyn (a, b, c) (a', b', c') Source # | |
Defined in Test.Method.Dynamic | |
(ToDyn a a', ToDyn b b', ToDyn c c', ToDyn d d') => ToDyn (a, b, c, d) (a', b', c', d') Source # | |
Defined in Test.Method.Dynamic | |
(ToDyn a a', ToDyn b b', ToDyn c c', ToDyn d d', ToDyn e e') => ToDyn (a, b, c, d, e) (a', b', c', d', e') Source # | |
Defined in Test.Method.Dynamic | |
(ToDyn a a', ToDyn b b', ToDyn c c', ToDyn d d', ToDyn e e', ToDyn f f') => ToDyn (a, b, c, d, e, f) (a', b', c', d', e', f') Source # | |
Defined in Test.Method.Dynamic | |
(ToDyn a a', ToDyn b b', ToDyn c c', ToDyn d d', ToDyn e e', ToDyn f f', ToDyn g g') => ToDyn (a, b, c, d, e, f, g) (a', b', c', d', e', f', g') Source # | |
Defined in Test.Method.Dynamic |
The class Typeable
allows a concrete representation of a type to
be calculated.
typeRep#
Monitor
Usage
Production code
type ExampleMethod env = Int -> String -> RIO env ()
class HasExampleMethod env where
exampleL :: Lens' env (ExampleMethod env)
doit :: HasExampleMethod env => RIO env ()
doit = (do
invoke exampleL 2 "foo"
invoke exampleL 3 "foo"
invoke exampleL (-1) "bar"
invoke exampleL 3 "bar") catchAny
(const $ pure ())
Test code
data Env = Env { _example :: ExampleMethod env } makeLenses Env'' instance HasExampleMethod Env where exampleL = example exampleMock :: ExampleMethod exampleMock =mockup
$ dowhen
(args
((<0),anything
)) `thenAction
` throwString "negative n"when
anything
`thenReturn
` () env = Env exampleMock spec :: Spec spec = describe "doit" $ do before $withMonitor_
$ \monitor -> runRIO env $ local (exampleL %~watch
monitor) doit it "calls example _ \"foo\" twice" $ \logs -> do logs `shouldSatisfy
` ((==2) `times
`call
(args
(anything
, (=="foo")))) it "calls example (-1) \"bar\" once" $ \logs -> do logs `shouldSatisfy
` ((==1) `times
`call
(args
((==(-1)), (=="bar")))) it "does not call example 3 \"bar\" " $ \logs -> do logs `shouldSatisfy
` ((==0) `times
`call
(args
((==3), (=="bar"))))
References
data Monitor args ret Source #
Monitor arg ret
is an event monitor of methods,
which logs method calls.
is a function call eventEvent
args ret
Instances
(Eq args, Eq ret) => Eq (Event args ret) Source # | |
(Ord args, Ord ret) => Ord (Event args ret) Source # | |
Defined in Test.Method.Monitor.Internal compare :: Event args ret -> Event args ret -> Ordering # (<) :: Event args ret -> Event args ret -> Bool # (<=) :: Event args ret -> Event args ret -> Bool # (>) :: Event args ret -> Event args ret -> Bool # (>=) :: Event args ret -> Event args ret -> Bool # | |
(Show args, Show ret) => Show (Event args ret) Source # | |
watchBy :: (Method method, MonadUnliftIO (Base method)) => (Args method -> args) -> (Ret method -> ret) -> Monitor args ret -> method -> method Source #
watchBy fArgs fRet monitor method
decorates method
so that monitor
logs the method calls.
This function is suited for monitoring multiple methods.
fArgs
and fRet
is converter for arguments/return values of given method.
foo :: Int -> IO String foo = ... bar :: Int -> String -> IO () bar = ... data MonitorArgs = FooArgs Int | BarArgs (Int,String) deriving(Eq,Show) data MonitorRet = FooRet String | BarRet () deriving(Eq, Show) foo' :: Monitor MonitorArgs MonitorRet -> Int -> IO String foo' monitor = watch monitor (FooArgs . toTuple) FooRet foo bar' :: Monitor MonitorArgs MonitorRet -> Int -> String -> IO () bar' monitor = watch monitor (BarArgs . toTuple) BarRet bar
watch :: (Method method, MonadUnliftIO (Base method)) => Monitor (Args method) (Ret method) -> method -> method Source #
Simplified version of watchBy
. It is suitable to monitor single method.
withMonitor :: MonadIO m => (Monitor args ret -> m a) -> m (a, [Event args ret]) Source #
withMonitor f
calls f
with Monitor
,
and then returns monitored event logs during the function call
in addition to the return value of the function call
withMonitor_ :: MonadIO m => (Monitor args ret -> m ()) -> m [Event args ret] Source #
withMonitor_ f
calls f
with Monitor
, and returns event logs during the call.
Matcher for events
call :: Matcher args -> Matcher (Event args ret) Source #
matches method call whose arguments matches call
matchermatcher
times :: Matcher Int -> Matcher (Event args ret) -> Matcher [Event args ret] Source #
counts events that matches times
countMatcher eventMatchereventMatcher
,
and then the count matches countMatcher
Procedual api for monitor
listenEventLog :: MonadIO m => Monitor args ret -> m [Event args ret] Source #
Get current event logs from monitor
Protocol
Usage
Protocol is a DSL to write specification on communications between dependent methods. By using Protocol, you can specify
- how many times each method is called,
- what arguments are passed for each call, and
- in which order methods are called.
For example, let's test user creation logic signup
.
signup :: Service -> Username -> IO (Maybe UserId) signup svc username = ... type UserName = String type UserId = Int
This method depends on Service
, which consists of two methods.
findUser
: checks whether the user name is taken already,createUser
: creates a user with given user name.
data Service = Service{ findUser :: UserName -> IO (Maybe UserId), createUser :: UserName -> IO UserId }
Let's check the following specification of signup
method.
- If
findUser
returnsJust user
, it returnsNothing
without callingcreateUser
. - If
findUser
returnsNothing
, it callscreateUser
and returns the created user.
In order to write Protocol DSL, first you define a GADT functor that represents labels of dependent methods.
data Methods m where FindUser :: Methods (UserName -> IO (Maybe UserId)) CreateUser :: Methods (UserName -> IO UserId) deriving instance (Show (Methods m)) deriving instance (Eq (Methods m)) deriving instance (Ord (Methods m))
Then, you can write test for the specification.
spec :: Spec spec = do describe "signup" $ do let username = "user1" userId = 1 context "if`findUser`
returns `Just user`" $ it "return `Nothing` without calling`createUser`
" $ do -- Because env is stateful, it should be initialized for each test env <-protocol
$ dodecl
$whenArgs
FindUser (==username)`thenReturn`
Just userId -- mocking methods from protocol env. Each mock method raises an exception -- if it is called in a different way than that specified by the protocol. let service = Service { findUser =lookupMock
FindUser env, createUser =lookupMock
CreateUser env } signup service username `shouldReturn` Nothing -- Checks all calls specified by the protocol are called.verify
env it "call`createUser`
and return `Just userId`" $ do env <- protocol $ do findUserCall <-decl
$whenArgs
FindUser (==username)`thenReturn`
Nothingdecl
$whenArgs
CreateUser (==username)`thenReturn`
Just userId`dependsOn`
[findUserCall] let service = Service { findUser =lookupMock
FindUser env, createUser =lookupMock
CreateUser env } signup service username`shouldReturn`
Just userIdverify
env
Protocol DSL consists of method call declarations like:
decl
$whenArgs
FindUser (=="user1")`thenReturn`
Nothing
This declaration specifies that findUser
is called once with argument "user1"
and it returns Nothing
.
If findUser
is called with other argument, it raises an exception.
In protocol DSL, you can specify in which order methods are called, by using dependsOn
function.
For example:
findUserCall <-decl
$whenArgs
FindUser (=="user1")`thenReturn`
Nothingdecl
$whenArgs
CreateUser (=="user1")`thenReturn`
Nothing`dependsOn`
[findUserCall]
findUser
must be called before calling createUser
.
On the other hand, in the following example:
decl
$whenArgs
FindUser (=="user1")`thenReturn`
Nothingdecl
$whenArgs
CreateUser (=="user1")`thenReturn`
Nothing
the order of calling two methods does not matter.
However, each call declaration implicitly depends on the previous call declaration of the same method. For example:
decl
$whenArgs
FindUser (=="user1")`thenReturn`
Nothingdecl
$whenArgs
FindUser (=="user2")`thenReturn`
Just 1
findUser "user1"
must be called before findUser "user2"
is called.
References
protocol :: ProtocolM f a -> IO (ProtocolEnv f) Source #
Build ProtocolEnv
from Protocol DSL.
data ProtocolEnv f Source #
provides mock methods, where ProtocolEnv
ff
is a GADT functor that
represents the set of dependent methods.
decl :: IsMethodName f m => Call f m -> ProtocolM f CallId Source #
Declare a method call specification. It returns the call id of the method call.
whenArgs :: ArgsMatcher (Args m) => f m -> EachMatcher (Args m) -> CallArgs f m Source #
Specify the argument condition of a method call
dependsOn :: Call f m -> [CallId] -> Call f m Source #
Specify on which method calls the call depends.
:: forall f m. (IsMethodName f m, Show (AsTuple (Args m)), TupleLike (Args m), Method m, MonadIO (Base m)) | |
=> f m | name of method |
-> ProtocolEnv f | |
-> m |
Get the mock method by method name. Return a unstubed method (which throws exception for every call) if the behavior of the method is unspecified by ProtocolEnv
:: forall f m. (IsMethodName f m, Method m, MonadIO (Base m)) | |
=> (Args m -> String) | show function for the argument of method |
-> f m | name of method |
-> ProtocolEnv f | |
-> m |
Get the mock method by method name. Return a unstubed method (which throws exception for every call) if the behavior of the method is unspecified by ProtocolEnv. Use this function only if you want to customize show implementation for the argument of the method.
verify :: ProtocolEnv f -> IO () Source #
Verify that all method calls specified by Protocol DSL are fired.
Matcher
References
Basics
when :: Matcher a -> Matcher a Source #
synonym of id
function.
Use this function for improving readability
Matcher for method arguments
class TupleLike a where Source #
Instances
TupleLike Nil Source # | |
TupleLike (a :* (b :* (c :* (d :* (e :* (f :* (g :* Nil))))))) Source # | |
Defined in Control.Method.Internal | |
TupleLike (a :* (b :* (c :* (d :* (e :* (f :* Nil)))))) Source # | |
Defined in Control.Method.Internal | |
TupleLike (a :* (b :* (c :* (d :* (e :* Nil))))) Source # | |
Defined in Control.Method.Internal | |
TupleLike (a :* (b :* (c :* (d :* Nil)))) Source # | |
TupleLike (a :* (b :* (c :* Nil))) Source # | |
TupleLike (a :* (b :* Nil)) Source # | |
TupleLike (a :* Nil) Source # | |
class TupleLike a => ArgsMatcher a where Source #
Matcher for Args
>>>
args ((==2), (>3)) (2 :* 4 :* Nil)
True>>>
args even (1 :* Nil)
False>>>
args () Nil
True
args :: EachMatcher a -> Matcher a Source #
Convert a tuple of matchers to a matcher of tuples
Instances
ArgsMatcher Nil Source # | |
Defined in Test.Method.Matcher type EachMatcher Nil Source # | |
ArgsMatcher (a :* (b :* (c :* (d :* (e :* (f :* (g :* Nil))))))) Source # | |
ArgsMatcher (a :* (b :* (c :* (d :* (e :* (f :* Nil)))))) Source # | |
ArgsMatcher (a :* (b :* (c :* (d :* (e :* Nil))))) Source # | |
ArgsMatcher (a :* (b :* (c :* (d :* Nil)))) Source # | |
ArgsMatcher (a :* (b :* (c :* Nil))) Source # | |
ArgsMatcher (a :* (b :* Nil)) Source # | |
ArgsMatcher (a :* Nil) Source # | |
Defined in Test.Method.Matcher type EachMatcher (a :* Nil) Source # |