(<$>) is infix "fmap"
(<*>) is infix "ap"
The "fmap" function lets you apply something of the form (a -> b) to a value of the form (m a), to get something of the form (m b). Specialized to lists, it's the familiar "map" function, but there are a lot of other things it can apply to.The "ap" function lets you apply a "wrapped" function to a "wrapped" value - "apply this list of functions to that list of values".
The way these combine, along with currying, means you get a well known pattern for applying a many argument function to many wrapped values:
<$> before the first argument
<*> before every remaining argument
It works out like this: let add3 :: Integer -> Integer -> Integer -> Integer
add3 x y z = x + y + z
(add3 5) :: Integer -> Integer -> Integer
(add3 <$> Just 5) :: Maybe (Integer -> Integer -> Integer)
(add3 <$> Just 5 <*> Just 3) :: Maybe (Integer -> Integer)
(add3 <$> Just 5 <*> Just 3 <*> Just 9) :: Maybe IntegerConcretely, if you think about promises in JavaScript, for example, if you have a function A -> B -> C -> D, say, and you have three promises of types Promise A, Promise B and Promise C, you can construct a Promise of type Promise D by running the three in parallel, and applying your three-argument function when they are all done. So you've turned a function of type A -> B -> C -> D into one of type Promise A -> Promise B -> Promise C -> Promise D. If you can do that sensibly for any number of function arguments, you have an Applicative. ("sensibly" here means that there are type class laws which have to hold)
Every Monad is also an Applicative functor, since you could use do notation to compose your promises instead, but there are other interesting Applicatives which do not come from Monads.
My favorite example is "I want to grab three web pages concurrently and return them in a single triple." To the haters who think this is just golf, just TRY to write this as beautifully in any other language.
(page1, page2, page3)
<- runConcurrently $ (,,)
<$> Concurrently (getURL "url1")
<*> Concurrently (getURL "url2")
<*> Concurrently (getURL "url3")
(taken from the excellent haddocks for Control.Current.Async https://hackage.haskell.org/package/async-2.0.1.4/docs/Contr...) val (page1, page2, page3) = (spawn getURL "url1",
spawn getURL "url2",
spawn getURL "url3")
The requests are concurrent. Spawn returns a future and 'page1', etc are futures immediately. When the value of 'page1', etc is requested later the requesting process either blocks until the getURL for that value is complete, or transforms into the value implicitly if it's already done.I think it's just as nice as the Haskell example. I do agree that Haskell is a great language though.