7

それぞれ同じ型のリストを生成する 2 つの引数 (x と y)を持つ 3 つの関数 ( getRowgetColumn、 ) があります。getBlock出力を連結する 4 番目の関数を書きたいと思います。

outputList :: Int -> Int -> [Maybe Int]
outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]

関数は機能しますが、二重マップ (3 つの「$」を含む) を単一マップに書き換える方法はありますか?

4

3 に答える 3

23
import Data.Monoid

outputList :: Int -> Int -> [Maybe Int]
outputList = mconcat [getRow, getColumn, getBlock]

あなたには説明が必要です。

まず、これらの関数はすべて同じ型であることに注意してください。

outputList, getRow, getColumn, getBlock :: Int -> Int -> [Maybe Int]

それでは、元の定義から始めましょう。

outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]

これらの関数は[Maybe Int]になり、何かのリストはモノイドです。リストをモノイド的に結合することは、リストを連結することと同じであるため、 に置き換えることができconcatますmconcat

outputList x y = mconcat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]

結果がモノイドである場合、モノイドである別のものは関数です。つまり、bがモノイドなら、a -> bもモノイドです。関数をモノイド的に結合することは、同じパラメーターで関数を呼び出し、結果をモノイド的に結合することと同じです。

したがって、次のように単純化できます

outputList x = mconcat $ map ($ x) [getRow,getColumn,getBlock]

そして再び

outputList = mconcat [getRow,getColumn,getBlock]

終わったね!


Typeclassopedia には monoids に関するセクションがありますが、この場合、 Data.Monoid のドキュメントをはるかに超えて追加されるかどうかはわかりません。

于 2012-09-27T10:46:36.857 に答える
4

最初のステップとして、私たちはあなたの定義を観察します

outputList x y = concat . map ($ y) $ map ($ x) [getRow,getColumn,getBlock]

(.)は、関数適用演算子の代わりに関数合成演算子を使用して($)次のように書き換えることができます。

outputList x y = (concat . map ($ y) . map ($ x)) [getRow,getColumn,getBlock]

次に、 はon リストmapの別の名前であり、法則を満たしていることに気付きます。したがって、特に、 があります。この法則を適用して、 の 1 つのアプリケーションを使用してバージョンを定義します。fmapfmapmap (f . g) == map f . map gmap

outputList x y = (concat . map (($ y) . ($ x))) [getRow,getColumn,getBlock]

concat最後のステップとして、との構成をmapで置き換えることができconcatMapます。

outputList x y = concatMap (($ y) . ($ x)) [getRow,getColumn,getBlock]

最後に、私の意見では、Haskell プログラマーは多くの派手な演算子を使用する傾向がありますが、関数を次のように定義することは恥ずべきことではありません。

 outputList x y = concatMap (\f -> f x y) [getRow,getColumn,getBlock]

それが明確に表現しているように、関数が何をするか。ただし、型クラスの抽象化 (他の回答で示されているように) を使用することは、問題に特定の抽象構造があり、新しい洞察を得ることができるため、良いことです。

于 2012-09-27T11:01:38.193 に答える