views:

329

answers:

5

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

+6  A: 

From Time flies like an applicative functor:

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!

Greg Bacon
+3  A: 

Conal Elliot 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
yairchu
Can you explain what the code is doing?
Daniel Velkov
@djv: I can, but doing it would require much context about the rest of the code, so I can't really do a brief explanation. I intend to finish my game and then perhaps make a blog post about it sometime soon. Till then, I hope my code (with context) is somewhat self-explanatory. cheers
yairchu
A: 

IO is also an instance of Applicative, you can do things like: (++) <$> getLine <*> getLine and the behaviour is as expected, the effects happen from left to right and (++) is lifted.

Another good example is parsing with applicative combinators, here is a good introduction and also this chapter from Real World Haskell is recommended.

Daniel Velkov
All these happen to be monads, though. The OP seeks non-monadic examples.
Michał Marczyk
But they are also applicative functors and are used as such.
Daniel Velkov
So what's your point?
trinithis
That parsing is a fine example of using applicative functors.
Daniel Velkov
+1  A: 

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

Paul Johnson
+2  A: 

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.

jrockway
Actually this does come from a monad, with `join ((a, _, _, _), (_, b, _, _), (_, _, c, _), (_, _, _, d)) = (a, b, c, d)` (up to newtypes). It is isomorphic (maybe only disregarding _|_s) to the `Reader T` monad where `T` is a type with four values.
Reid Barton