Re: Contravariant applicatives, monads and arrows (was ANN: rematch, an library for composable assertions with human readable failure messages)
Roman Cheplyaka <roma <at> ro-che.info>
2013-04-18 02:11:46 GMT
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
myProp = proc list -> do
mbItem <- everyItem -< list
item <- hasJust -< mbItem
is 3 -< item
* Alejandro Serrano Mena <trupill <at> gmail.com> [2013-04-16 17:12:51+0200]
> 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