16 Apr 2013 17:12

## Contravariant applicatives, monads and arrows (was ANN: rematch, an library for composable assertions with human readable failure messages)

Hi,
First of all, let me say that this work on matchers is really useful :)

Following Roman advice, I'm trying to find a more principled approach
that could be useful for this library. It seems that "Match" could
easily be converted to Either and thus made into Functor, Applicative,
Alternative and Monad. That would allow to write things like:

User <\$> runMatch (isNot isEmpty) name <*> runMatch (hasItem (is ' <at> ')) email

However, I'm also thinking about the correct way to "combine" matchers
to get bigger matchers. Basically, if I have matchers on every field
of a record, can I get a matcher for the entire one?

My first idea was to make Matcher a functor. However, what I come was
a contravariant functor: given (a -> b) and Matcher b, I can easily
construct a Matcher a by running the one in b over this function. So
we have:

contramap :: (a -> b) -> Matcher b -> Matcher a

My first question is: is there any structure similar to applicative
functors or monads which work on these kind of contravariant functors?
This also brought into my mind to see Matcher a just as functions a ->
Match and derive its properties from there. This may give better
results that the above mentioned idea of looking it as a -> Either
String a, because in this latter case we have a in covariant and
contravariant positions and it's difficult to get anything.

On the other hand, it seems very easy, from a Matcher a and a Matcher

16 Apr 2013 17:42

### Re: Contravariant applicatives, monads and arrows (was ANN: rematch, an library for composable assertions with human readable failure messages)

My idea was to convert Matcher to be a covariant functor.

It would be essentially a Matcher which has been applied to the tested
value.

And the type argument would denote the result of a computation. For
example, consider

hasRight :: (Show a, Show b) => Matcher b -> Matcher (Either a b)

hasRight :: F (Either a b) -> F b

... and you then could test 'b' further. F, of course, would handle
errors. But also it could record the chain of functions, so that it
could print it in case of failure, like it Tom's code.

(I guess that means that F has to be a monad. Also it (intentionally)
wouldn't satisfy any usual laws, because we need to record all the
computational steps.)

Or, indeed, you could both preserve the input and add an output, which
would make it a profunctor (and probably a category/arrow).

Roman

* Alejandro Serrano Mena <trupill <at> gmail.com> [2013-04-16 17:12:51+0200]
> Hi,
> First of all, let me say that this work on matchers is really useful :)

16 Apr 2013 20:48

### Re: Contravariant applicatives, monads and arrows (was ANN: rematch, an library for composable assertions with human readable failure messages)

On 16 April 2013 16:12, Alejandro Serrano Mena <trupill <at> gmail.com> wrote:
> Hi,
> First of all, let me say that this work on matchers is really useful :)
>
> Following Roman advice, I'm trying to find a more principled approach
> that could be useful for this library. It seems that "Match" could
> easily be converted to Either and thus made into Functor, Applicative,
> Alternative and Monad. That would allow to write things like:
>

Have you seen Ralf Hinze, Johan Jeuring and Andreas Loeh's  paper on Contracts?

The found their Contract datatype formed a comonad - at the time this
seemed to be one of the few (non-synthetic) uses of comonads.
18 Apr 2013 00:57

### Re: Contravariant applicatives, monads and arrows (was ANN: rematch, an library for composable assertions with human readable failure messages)

* Stephen Tetley <stephen.tetley <at> gmail.com> [2013-04-16 19:48:47+0100]
> On 16 April 2013 16:12, Alejandro Serrano Mena <trupill <at> gmail.com> wrote:
> > Hi,
> > First of all, let me say that this work on matchers is really useful :)
> >
> > Following Roman advice, I'm trying to find a more principled approach
> > that could be useful for this library. It seems that "Match" could
> > easily be converted to Either and thus made into Functor, Applicative,
> > Alternative and Monad. That would allow to write things like:
> >
>
>
> Have you seen Ralf Hinze, Johan Jeuring and Andreas Loeh's  paper on Contracts?
>
> The found their Contract datatype formed a comonad - at the time this
> seemed to be one of the few (non-synthetic) uses of comonads.

Their Contract datatype is contravariant, just like Tom's Matcher. So it

It's their "contracted function" type which is a (very simple) comonad —
but I'm not sure how it can be useful here.

(I only skipped very quickly through the paper, so I may be missing
something.)

Roman

_______________________________________________

16 Apr 2013 22:52

### Re: Contravariant applicatives, monads and arrows (was ANN: rematch, an library for composable assertions with human readable failure messages)

The type looks similar to the denotation for sets, but implementing a covariant interface for it would not be straightforward and may also be inefficient.

On Apr 16, 2013 11:17 AM, "Alejandro Serrano Mena" <trupill <at> gmail.com> wrote:
Hi,
First of all, let me say that this work on matchers is really useful :)

Following Roman advice, I'm trying to find a more principled approach
that could be useful for this library. It seems that "Match" could
easily be converted to Either and thus made into Functor, Applicative,
Alternative and Monad. That would allow to write things like:

User <\$> runMatch (isNot isEmpty) name <*> runMatch (hasItem (is ' <at> ')) email

However, I'm also thinking about the correct way to "combine" matchers
to get bigger matchers. Basically, if I have matchers on every field
of a record, can I get a matcher for the entire one?

My first idea was to make Matcher a functor. However, what I come was
a contravariant functor: given (a -> b) and Matcher b, I can easily
construct a Matcher a by running the one in b over this function. So
we have:

contramap :: (a -> b) -> Matcher b -> Matcher a

My first question is: is there any structure similar to applicative
functors or monads which work on these kind of contravariant functors?
This also brought into my mind to see Matcher a just as functions a ->
Match and derive its properties from there. This may give better
results that the above mentioned idea of looking it as a -> Either
String a, because in this latter case we have a in covariant and
contravariant positions and it's difficult to get anything.

On the other hand, it seems very easy, from a Matcher a and a Matcher
b, to get a Matcher (a,b). This reminds me a bit about arrows, but
without output parameters. Does it make sense? I've always been
reluctant to arrows because I don't fully understand them, but maybe
this is a good moment to learn.

Do any of this make sense? I would really like to contribute to this
great library! :)

2013/4/16 Tom Crayford <tcrayford <at> gmail.com>:
> Roman,
>
> Thanks for the feedback! I'd originally left the QuickCheck and HUnit
> implementations in this library for convenience, thinking that there aren't
> going to be many people who care about the transitive dep. But you care, so
> I'm happy moving them out of core. I'll release a 0.2 with both the HUnit
> and the QuickCheck runners in separate libraries soonish.
>
> Thanks for the haddock tip and the implementation tips.
>
> Re the Control namespace, these matchers aren't exclusively a testing tool.
> I've been using the core api for other purposes as well (primarily for
> validating forms in user interfaces in conjunction with digestive-functors).
> I couldn't figure anything better to put it in apart from Control (I
> definitely don't want it in Test, even though that's going to be what most
> people use it for). I guess it could be in `Data`, but that doesn't sound
> much better to me.
>
> I'm not amazingly strong at building more principled interfaces right now,
> so I guess that's something I'll improve on. Are there any concrete
> suggestions you have there? I'd *like* these to have an `Alternative`
> instance, but making `Applicative`/`Functor` instances is beyond me right
> now (I guess I'd have to change the core API for that to work out).
>
> Tom
>
>
> ...

_______________________________________________
_______________________________________________
18 Apr 2013 04:11

### Re: Contravariant applicatives, monads and arrows (was ANN: rematch, an library for composable assertions with human readable failure messages)

You are right Alejandro, arrows are a perfect fit here. (Most of it
is possible with monads as well, but arrows are useful to maintain
static names of the properties.)

Here's what I've come up with: https://gist.github.com/feuerbach/5409326

Now everyItem and hasJust have types

everyItem :: Matcher [a] a
hasJust :: Matcher (Maybe a) a

(similarly for all other functions)

This allows us to write

myProp = everyItem >>> hasJust >>> is 3

or even

myProp = proc list -> do
mbItem <- everyItem -< list
item <- hasJust -< mbItem
is 3 -< item

Roman

* Alejandro Serrano Mena <trupill <at> gmail.com> [2013-04-16 17:12:51+0200]
> Hi,
> First of all, let me say that this work on matchers is really useful :)
>
> Following Roman advice, I'm trying to find a more principled approach
> that could be useful for this library. It seems that "Match" could
> easily be converted to Either and thus made into Functor, Applicative,
> Alternative and Monad. That would allow to write things like:
>
> User <\$> runMatch (isNot isEmpty) name <*> runMatch (hasItem (is ' <at> ')) email
>
> However, I'm also thinking about the correct way to "combine" matchers
> to get bigger matchers. Basically, if I have matchers on every field
> of a record, can I get a matcher for the entire one?
>
> My first idea was to make Matcher a functor. However, what I come was
> a contravariant functor: given (a -> b) and Matcher b, I can easily
> construct a Matcher a by running the one in b over this function. So
> we have:
>
> contramap :: (a -> b) -> Matcher b -> Matcher a
>
> My first question is: is there any structure similar to applicative
> functors or monads which work on these kind of contravariant functors?
> This also brought into my mind to see Matcher a just as functions a ->
> Match and derive its properties from there. This may give better
> results that the above mentioned idea of looking it as a -> Either
> String a, because in this latter case we have a in covariant and
> contravariant positions and it's difficult to get anything.
>
> On the other hand, it seems very easy, from a Matcher a and a Matcher
> b, to get a Matcher (a,b). This reminds me a bit about arrows, but
> without output parameters. Does it make sense? I've always been
> reluctant to arrows because I don't fully understand them, but maybe
> this is a good moment to learn.
>
> Do any of this make sense? I would really like to contribute to this
> great library! :)
>
> 2013/4/16 Tom Crayford <tcrayford <at> gmail.com>:
> > Roman,
> >
> > Thanks for the feedback! I'd originally left the QuickCheck and HUnit
> > implementations in this library for convenience, thinking that there aren't
> > going to be many people who care about the transitive dep. But you care, so
> > I'm happy moving them out of core. I'll release a 0.2 with both the HUnit
> > and the QuickCheck runners in separate libraries soonish.
> >
> > Thanks for the haddock tip and the implementation tips.
> >
> > Re the Control namespace, these matchers aren't exclusively a testing tool.
> > I've been using the core api for other purposes as well (primarily for
> > validating forms in user interfaces in conjunction with digestive-functors).
> > I couldn't figure anything better to put it in apart from Control (I
> > definitely don't want it in Test, even though that's going to be what most
> > people use it for). I guess it could be in `Data`, but that doesn't sound
> > much better to me.
> >
> > I'm not amazingly strong at building more principled interfaces right now,
> > so I guess that's something I'll improve on. Are there any concrete
> > suggestions you have there? I'd *like* these to have an `Alternative`
> > instance, but making `Applicative`/`Functor` instances is beyond me right
> > now (I guess I'd have to change the core API for that to work out).
> >
> > Tom

Gmane