`Trade`

from an association list. We used monadic lifts (`liftM`

) and monadic apply (`ap`

) to chain our builder that builds up the Trade data. Here's what we did ..`makeTrade :: [(String, Maybe String)] -> Maybe Trade`

makeTrade alist =

Trade `liftM` lookup1 "account" alist

`ap` lookup1 "instrument" alist

`ap` (read `liftM` (lookup1 "market" alist))

`ap` lookup1 "ref_no" alist

`ap` (read `liftM` (lookup1 "unit_price" alist))

`ap` (read `liftM` (lookup1 "quantity" alist))

lookup1 key alist = case lookup key alist of

Just (Just s@(_:_)) -> Just s

_ -> Nothing

Immediately after the post, I got some useful feedback on Twitter suggesting the use of applicatives instead of monads. A Haskell newbie, that I am, this needed some serious explorations into the wonderful world of functors and applicatives. In this post let's explore some of the goodness that applicatives offer, how using applicative style of programming encourages a more functional feel and why you should always use applicatives unless you need the special power that monads offer.

**Functors and Applicatives**

In Haskell a functor is a typeclass defined as

`class Functor f where`

fmap :: (a -> b) -> f a -> f b

**fmap**lifts a pure function into a computational context. For more details on functors, applicatives and all of typeclasses, refer to the Typeclassopedia that Brent Yorgey has written. In the following text, I will be using examples from our domain model of securities trading. After all, I am trying to explore how Haskell can be used to build expressive domain models with a very popular domain at hand.

Consider the association list

`rates`

from our domain model in my last post, which stores pairs of tax/fee and the applicable rates as percentage on the principal.`*Main> rates`

[(TradeTax,0.2),(Commission,0.15),(VAT,0.1)]

We would like to increase all rates by 10%.

`fmap`

is our friend here ..`*Main> fmap (\(tax, amount) -> (tax, amount * 1.1)) rates`

[(TradeTax,0.22000000000000003),(Commission,0.165),(VAT,0.11000000000000001)]

This works since

`List`

is an instance of the `Functor`

typeclass. The anonymous function gets lifted into the computational context of the `List`

data type. But the code looks too verbose, since we have to destructure the tuple within the anonymous function and thread the increment logic manually within it. We can increase the level of abstraction by making the tuple itself a functor. In fact it's so in Haskell and the function gets applied to the second component of the tuple. Here's the more idiomatic version ..`*Main> ((1.1*) <$>) <$> rates`

[(TradeTax,0.22000000000000003),(Commission,0.165),(VAT,0.11000000000000001)]

Note how we lift the function across 2 levels of functors - a list and within that, a tuple. fmap does the magic! The domain model becomes expressive through the power of Haskell's higher level of abstractions.

Applicatives add more power to functors. While functors lift pure functions, with applicatives you can lift functions from one context into another. Here's how you define the

`Applicative`

typeclass.`class Functor f => Applicative f where`

pure :: a -> f a

(<*>) :: f (a -> b) -> f a -> f b

Note

`pure`

is the equivalent of a `return`

in monads, while `<*>`

equals `ap`

. `Control.Applicative`

also defines a helper function `<$>`

, which is basically an infix version of `fmap`

. The idea is to help write functions in applicative style.`(<$>) :: Applicative f => (a -> b) -> f a -> f b`

Follow the types and see that

`f <$> u`

is the same as `pure f <*> u`

.Note also the following equivalence of

`fmap`

and `<$>`

..`*Main> fmap (+3) [1,2,3,4]`

[4,5,6,7]

*Main> (+3) <$> [1,2,3,4]

[4,5,6,7]

Using the applicative style our

`makeTrade`

function becomes the following ..`makeTrade :: [(String, Maybe String)] -> Maybe Trade`

makeTrade alist =

Trade <$> lookup1 "account" alist

<*> lookup1 "instrument" alist

<*> (read <$> (lookup1 "market" alist))

<*> lookup1 "ref_no" alist

<*> (read <$> (lookup1 "unit_price" alist))

<*> (read <$> (lookup1 "quantity" alist))

Can you figure out how the above invocation works ? As I said before, follow the types ..

`Trade`

is a pure function and `<$>`

lifts `Trade`

onto the first invocation of `lookup1`

, which is a `Maybe`

functor. The result is another `Maybe`

, which BTW is an Applicative functor as well. Then the rest of the chain continues through partial application and an applicative lifting from one context to another.**Why choose Applicatives over Monads ?**

One reason is that there are more applicatives than monads. Monads are more powerful - using

`(>>=) :: (Monad m) => m a -> (a -> m b) -> m b`

you can influence the structure of your overall computation, while with applicatives your structure remains fixed. You only get sequencing of effects with an applicative functor. As an exercise try exploring the differences in the behavior of `makeTrade`

function implemented using monadic lifts and applicatives when `lookup1`

has some side-effecting operations. Conor McBride and Ross Paterson has a great explanation in their functional pearl paper Applicative Programming with Effects. Applicatives being more in number, you have more options of abstracting your domain model.In our example domain model, suppose we have the list of tax/fees and the list of rates for each of them. And we would like to build our rates data structure.

`ZipList`

applicative comes in handy here .. `ZipList`

is an applicative defined as follows ..`instance Applicative ZipList where `

pure x = ZipList (repeat x)

ZipList fs <*> ZipList xs = ZipList (zipWith (\f x -> f x) fs xs)

*Main> getZipList $ (,) <$> ZipList [TradeTax, Commission, VAT] <*> ZipList [0.2, 0.15, 0.1]

[(TradeTax,0.2),(Commission,0.15),(VAT,0.1)]

`ZipList`

is an applicative and NOT a monad.Another important reason to choose applicatives over monads (but only when possible) is that applicatives compose, monads don't (except for certain pairs). The McBride and Paterson paper has lots of discussions on this.

Finally programs written with applicatives often have a more functional feel than some of the monads with the

`do`

notation (that has an intrinsically imperative feel). Have a look at the following snippet which does the classical do-style first and then follows it up with the applicative style using applicative functors.`-- classical imperative IO`

notice = do

trade <- getTradeStr

forClient <- getClientStr

putStrLn $ "Trade " ++ trade ++ forClient

-- using applicative style

notice = do

details <- (++) <$> getTradeStr <*> getClientStr

putStrLn $ "Trade " ++ details

McBride and Paterson has the final say on how to choose monads or applicatives in your design ..

*"The moral is this: if you’ve got an Applicative functor, that’s good; if you’ve also got a Monad, that’s even better! And the dual of the moral is this: if you want a Monad, that’s good; if you only want an Applicative functor, that’s even better!"*

**Applicative Functors for Expressive Business Rules**

As an example from our domain model, we can write the following applicative snippet for calculating the net amount of a trade created using

`makeTrade`

..`*Main> let trd = makeTrade [("account", Just "a-123"), ("instrument", Just "IBM"), `

("market", Just "Singapore"), ("ref_no", Just "r-123"),

("unit_price", Just "12.50"), ("quantity", Just "200" )]

*Main> netAmount <$> enrichWith . taxFees . forTrade <$> trd

Just 3625.0

Note how the chain of functions get lifted into trd (

`Maybe Trade`

) that's created by `makeTrade`

. This is possible since `Maybe`

is an applicative functor. The beauty of applicative functors is that you can abstract this lifting into any of them. Let's lift the chain of invocation into a list of trades generating a list of net amount values for each of them. Remember `List`

is also another applicative functor in Haskell. For a great introduction to applicatives and functors, go read Learn Yourself a Haskell for Great Good.`*Main> (netAmount <$> enrichWith . taxFees . forTrade <$>) <$> [trd2, trd3]`

[Just 3625.0,Just 3375.0]

Look how we have the minimum of syntax with this applicative style. This makes business rules very expressive and not entangled into a maze of accidental complexity.

## 6 comments:

You forget telling readers that <$> is the operator for infix fmap before <$> shows up.

I'm not familiar with Applicatives...

I was wondering how one would write a variation of your example of increasing all rates by 10%:

((1.1*) <$>) <$> ratesthat would increase tax by 10%.

Sergio

@Anonymous ..

((1.1*) <$> ) <$> (filter(\(x, _) -> x == TradeTax) rates)

I like that ((->) r) is also a Functor instance, so we can

re-define (.) to be fmap and get function composition for

free. In GHCi:

λ> let f . g = fmap f g

λ> :t (.)

(.) :: (Functor f) => (a -> b) -> f a -> f b

The following works fine:

λ> ((*4) . (+4)) . [1..5]

[20,24,28,32,36]

So instead of,

λ> ((1.1*)<$>) <$> [Just 5,Just 2]

[Just 5.5,Just 2.2]

you can write

λ> ((1.1*).) . [Just 5,Just 2]

[Just 5.5,Just 2.2]

Pretty nice.

Instead of all those references to 'alist', you could have defined 'lookup x = lookup1 x alist' in a where clause inside mkTrade. That would make it cleaner IMHO.

@Christopher: I would advise against your approach. It is useful to observe that the fmap instance for ((->) r) is (.). On the other hand, you have shown the opposite: redefining (.) as fmap is not the same at all, and highly confusing.

Post a Comment