简体   繁体   中英

Applicative functors other than monads and ZipList?

Two well-known examples of applicatives are monads and ziplists. Are there any other examples?

From Time flies like an applicative functor by Conor McBride:

Structure cops will note that De is another example of an applicative functor which is not a monad — join would bring things from the far future to the near future, and that had better not be possible. However, where applicative functors in general only pull through traversable functors (containers with finitely many elements), De pulls through all containers. So it's a bit special. I wonder what it is.

and

The De functor represents a fixed delay, rather than an arbitrary one. I'm dividing time into discrete slices. De x is the type of an x due at the next slice. De (De x) is thus the type of an x due in two slices' time, and you can't make it turn up any sooner!

Read the whole post. To answer the immediate question, the author's conclusion is

Don't Look!

OK, here's the implementation. It's a con.

 newtype De x = De x deriving Show -- ssh, don't tell! instance Functor De where fmap f (De x) = De (fx) instance Applicative De where pure = De De f <*> De s = De (fs) fix :: (De x -> x) -> x fix f = f (De (fix f)) 

I recently defined an Applicative instance for a newtype on top of (,,,) , a "quad". (The standard library defines an instance for (,) , but not (,,,) . That's OK, as the standard implementation has different semantics than what I was after.)

The background is; I am parsing some old data, and the date format in the data is ambiguous. Each date in the data can be parsed into four possibilities, stored in the quad. I then want to validate each date in the quad to eliminate semantically invalid dates. (There are no months with 32 days, there is no month 34, there is no 5th quarter, etc.) Finally, I want to take each date in the dataset, and reduce the entire set to a quad representing which date formats are valid for the entire set. Then, I choose the best format out of those options, and assume that's what the date format of the dataset is.

This entire operation is very easy to express as applicative operations on the quad structure.

Here's the basic shape of the code:

My new type:

newtype DQ a = DQ (a, a, a, a) -- date quad
             deriving ...

instance Functor DQ where
   g `fmap` f = pure g <*> f

instance Applicative DQ where
   pure x  = DQ (x, x, x, x)
   DQ (g, h, i, j) <*> DQ (a, b, c, d) = DQ (g a, h b, i c, j d)

Some prerequisite "pure" functions:

parseDateInt :: Int -> DQ Date
validateDate :: Date -> Bool
extractBestDate :: DQ Date -> DQ Bool -> Date

So once we have the quad of parsed dates (from parseDateInt ), we need to validate them:

validateDates :: DQ Date -> DQ Bool
validateDates = (validateDate <$>)

(This is only a Functor so far, but you could also write (pure validateDate <*>) .

It's also worth noting the symmetry between validation of a single element, and validating each element of the set -- to validate one, you might write validateDate $ date ; to validate a set, you write validateDate <$> dates . This is why fmap is written as <$> , it's function application to a functor.)

The step after this is to take a set of valid parses and fold that into a final result:

intuitDateType :: [DQ Bool] -> DQ Bool
intuitDateType dates = foldl1 (liftA2 (&&)) dates

So now you can go from the [Int] in the data file to a DQ Bool representing the possibly-valid date representations for a dataset. (And from there, associate each data point with a real date object, instead of the flaky Int that was supplied.)

So anyway, this post has gotten a bit long, but the idea is that an Applicative instance allowed me to solve my problem in about 3 lines of code. My problem domain was repeatedly applying functions to data in a container, which is what an Applicative functor does. There is no join operation on this data, so a Monad instance would not make much sense.

Conal Elliott writes about signal processors and how they're applicatives . Those are similar to ZipList in nature, where each respective pair of items in the two "containers" gets combined.

I've been using this concept a lot in an unfinished yet cute game I made ( cabal install DefendTheKing to check it out).

Code snippet/example of Applicative-style usage:

draw font
<$> lstP gABoard
<*> lstP gASelection
<*> mouseMotion
<*> lstP gASide
<*> lstP gAGameIteration

Formlets are an abstraction over HTML forms described in terms of composing applicatives. A formlet applicative is the result of composing a name generating applicative (to generate form elements names), a XML writer applicative (to generate HTML), and an environment applicative (to supply the submitted form values).

Formlets can be extended by composing additional applicatives, for example to implement validation.

Cooper, Wadler et al show in the papers that formlets cannot be represented as monads.

Formlets have been implemented in Haskell, here is the package .

Swierstra and Duponcheel defined an efficient style of parser, this parser was pretty much the early poster child for Arrows, but it doesn't need anything from Arrow that it can't get from Applicative. However, Applicatives hadn't been coined at the time.

Effectively it computes 'FIRST' sets for an LL(1) parser and uses that to do smarter branch selection. However, you can't compute these sets when you work monadically.

This is perhaps not a terribly fair example, because the Swierstra/Duponcheel parser admits a blending of static and dynamic parsers, and it is only the static parser that is limited to being applicative.

With observable sharing you can carry their parser design farther and also compute 'FOLLOW' sets (as long as you are careful to not build an infinite context free grammar.). This yields nice asymptotic guarantees for parsing context free grammars, which are not available to you when parsing using monadic (context sensitive) parser designs.

Also interesting perhaps, is to consider the structures for which the <*> of applicative is available, but not the pure. Many comonads admit a (<*>)-like definition, which respects the structure of the comonad, but don't have a reasonable definition for 'pure'. My semigroupoids package and the myriad packages that depend upon it explore this idea further.

I believe arrows are applicative functors. There is certainly a WrapArrow type in Control.Applicative.

McBride和Paterson http://www.soi.city.ac.uk/~ross/papers/Applicative.pdf表明,monoid可以被视为一个应用函子,但一般情况下它不是monad。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM