25

私は次のコードを書きました。このコードは、一連のポイントを取得し、gloss ライブラリを使用して画面に描画します。

let s = blocks pes
    pts = map (map mkPt) s  {- stitches to points-}
    lines = map Line pts    {-points to lines -}
    pict = Pictures lines   {- lines to a picture -}
  in do  displayInWindow "My Window" (200, 200) (10, 10) white pict

それは正常に動作しますが、繰り返されるパターンがあることに気付きました。関数呼び出しのチェーンであり、それぞれの結果が次の最後の引数に供給されます。そこで、中間変数を削除してリファクタリングし、順序を逆にして、関数合成 (".") を使用して関数を次のように連鎖させました。

let pict = Pictures . (map Line) . (map $ map $ mkPt) . blocks $ pes
                in do  displayInWindow "My Window" (200, 200) (10, 10) white pict

幸いなことに、これも問題なく機能します。しかし、読みやすさに負担をかけているのか、それともポイントフリースタイルのコードの読み書きに慣れていないだけなのか疑問に思っています。また、このコードについてどのように推論すればよいですか? 2 番目のバージョンはより効率的ですか、それとも簡潔ですか? より明確にするためにスタイル的にできることはありますか?

4

2 に答える 2

31

いくつかの簡単な提案:

let pict = Pictures . (map Line) . (map $ map $ mkPt) . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict

完全に削除できる余分なものがいくつかあります。

let pict = Pictures . map Line . (map $ map mkPt) . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict

とにかくmap (map mkPt)用語で括弧を避けているわけではないので、 : を取り除きます$:

let pict = Pictures . map Line . map (map mkPt) . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict

わかりやすくするために、コンポジション チェーンを複数の行に記述することができます。

let pict = Pictures 
         . map Line 
         . map (map mkPt) 
         . blocks $ pes
in do displayInWindow "My Window" (200, 200) (10, 10) white pict

ブロックにはdoステートメントが 1 つしかないため不要であり、最終的なアプリケーションを定義の外に移動できます。

let displayPict = displayInWindow "My Window" (200, 200) (10, 10) white
                . Pictures 
                . map Line 
                . map (map mkPt) 
                . blocks
in displayPict pes

map2 つのをマージできます。

let displayPict = displayInWindow "My Window" (200, 200) (10, 10) white
                . Pictures 
                . map (Line . map mkPt) 
                . blocks
in displayPict pes

場合によっては、長いチェーンが逆合成演算子 from を使用する方が読みやすい場合もありますControl.Arrow

let displayPict = blocks
                  >>> map (Line . map mkPt) 
                  >>> Pictures
                  >>> displayInWindow "My Window" (200, 200) (10, 10) white
in displayPict pes

しかし、それはすべてオプションです。コードを味付けしてください。

GHC のオプティマイザがコードを処理し終わったら、効率性に関しては、この 2 つに違いがあると考える理由はないと思います。

于 2011-06-27T14:52:57.090 に答える
4

ポイント フリー スタイルは、関数が単に入力に対する一連の変換であることを非常に明確に示すのに適しています。次のようなものを読むのは本当に簡単です:

foo = map show . doThis . doThat . etc

典型的なポイントフリー コードのように見えるため、これに精通している人は重要なことをノイズなしで正確に確認できます。これを次と比較してください。

foo x = d
    where
        a = etc x
        c = doThis b
        b = doThat a
        d = map show c

明らかに、これは少し不自然ですが、実際に何が行われているのかを理解するには、余分な定義を読んで注意深く注意を払う必要があるという考えですfooa複数のヘルパー関数の引数として使用されていますか? どうbですか?データはこれらのヘルパー関数を予期しない方法で流れましたか? この場合のポイントフリースタイルは、「物事はパイプラインで変換されているだけで、考える必要のある奇妙なことはありません」と言います。

それ以外の場合、ポイントフリー スタイルは実際に物事を難読化する可能性があります。一般的には、let と where を分割するのはそのときです。つまり、簡潔にすることだけが目的ではなく、精神的負荷を軽減することも重要です。(他の人がコメントしているように、ポイントフリースタイルは最適化されたコードでパフォーマンスの違いを持つべきではありません)。

于 2011-06-29T17:49:25.760 に答える