10

Web アプリで小さなデータベース プールを使用しています。そして、この特定の機能:

withPool pool = bracket (takeConn pool) (putConn pool)

適用可能なスタイルで書き直すことができます:

withPool = bracket <$> takeConn <*> putConn

おそらく、それは読みやすく、はるかにエレガントです。当然、そのように書きたいと思います。しかし、データベース接続プールは高速であると想定されており、このスタイルでは不要なオーバーヘッドが発生するのではないかと心配しています。

だから私の質問は、Haskell で applicative functor を使用するとどのくらいのオーバーヘッドが発生するか (ある場合) です。ベンチマークはありますか?

4

2 に答える 2

19

ほとんどの場合、それらは同じものにコンパイルされると本当に思っています。ちょっとしたテストをしたのですが、

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

しかし、私はそこで test2 の型を関数のみに制限しています (これは最も一般化された型ではありません..?)

ghc -O -ddump-simpl次に、GHC からある種の中間出力を取得するために でコンパイルしました (C の出力を試してみましたが、あまりにも醜いものでした)。2 つの出力は、名前を除いてまったく同じに見えました。

(私も -O なしで試してみましたが、それらは同じではありませんでしたし、型注釈を省略した場合も同様でした)

于 2011-03-08T09:22:26.937 に答える
12

そのレベルのマイクロ最適化が心配な場合は、手動で組み立てる必要があります。

何よりもまず、明確で洗練されたコードを記述します。速度が問題になる場合は、プロファイリングを行い、ホットスポットを最適化してください。

Monad ((->) r) の定義がいかに単純かを考えると、GHC が定義をインライン化することを本当に信頼する必要があります。この時点で、2 つのバージョンはアルファの名前変更まで同一になります。

于 2011-03-08T15:38:15.850 に答える