I am using a small database pool in my web app. And this particular function:
withPool pool = bracket (takeConn pool) (putConn pool)
can be rewritten in applicative style:
withPool = bracket <$> takeConn <*> putConn
Arguably it is just as readable and much more elegant. So naturally, I want to write it like that. But database connection po开发者_如何学JAVAol supposed to be fast, and I am afraid that this style introduces unnecessary overhead.
So my question is, how much overhead (if any) does use of applicative functors incur in Haskell? Are there any benchmarks?
I really suspect they'll be compiled down to the same thing in most cases. I did a tiny test,
import Control.Applicative
test1 :: (b -> b -> c) -> (a -> b) -> (a -> b) -> a -> c
test1 bracket takeConn putConn pool = bracket (takeConn pool) (putConn pool)
test2 :: (b -> b -> c) -> (a -> b) -> (a -> b) -> a -> c
test2 bracket takeConn putConn = bracket <$> takeConn <*> putConn
but I am constraining the type of test2 there to only functions (which isn't its most generalised type, right..?)
Then I compiled with ghc -O -ddump-simpl
to get some sort of intermediate output from GHC (I tried the C output, it was too ugly) and the two came out looking exactly the same, except for names.
(I also tried without -O though, and they weren't the same, nor if I leave out the type annotations)
If you're worried about that level of micro-optimisation, you should be hand-rolling assembly.
Write clear and elegant code first and foremost. If speed is an issue, do some profiling and optimise the hot-spots.
Given how simple the definition of Monad ((->) r) is, you really should trust GHC to inline the definitions for you, at which point the two versions become identical up to alpha-renaming.
精彩评论