Computational cost of applicative style

2019-04-21 04:47发布

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 pool 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?

2条回答
我只想做你的唯一
2楼-- · 2019-04-21 05:05

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)

查看更多
狗以群分
3楼-- · 2019-04-21 05:07

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.

查看更多
登录 后发表回答