2012-09-27 2 views
5

私は2つの引数(xとy)を持つ3つの関数(getRowgetColumngetBlock)を持ち、それぞれが同じ型のリストを生成します。私は、その出力を連結する第4の機能書きたい:Haskellで複数の引数に渡って関数のリストをマッピングするには?

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

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

答えて

22
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]であり、何かのリストはモノイドです。リストを単項式に結合することはリストを連結することと同じであるため、concatmconcatに置き換えることができます。

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

もう1つのモノイドは、結果がモノイドの場合は関数です。つまり、bがモノイドの場合、a -> bもモノイドです。関数を単項式に結合することは、同じパラメータを持つ関数を呼び出してから、結果を単調に結合することと同じです。

だから我々は、我々が行っている

outputList = mconcat [getRow,getColumn,getBlock] 

に再び

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

に簡素化し、することができます!


Typeclassopedia has a section about monoids、この場合には、私はそれがdocumentation for Data.Monoidを超えてそのくらいが追加されますかわからないが。

4

は、最初のステップとして、私たちはあなたの定義

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

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

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

次はmapしたがって、特に、我々はmap (f . g) == map f . map gを持って、リストを満たすfmap法律上fmapのための別の名前であることに気づきます。 mapという単一のアプリケーションを使用して、この法律を適用してバージョンを定義します。

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

は、最後のステップとして、我々はconcatMapによってconcatmapの構図を置き換えることができます。Haskellのプログラマは、多くの派手な演算子を使用する傾向があるものの

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

は最後に、私の意見では、明らかに機能が何をするか、表現として

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

で関数を定義するための恥ではありません。しかし、(他の答えに示されているように)型クラス抽象化を使用することは、問題が特定の抽象的な構造を持ち、新しい洞察を得ることができるので、良いことです。

2

私は@ dave4420の答えに行くでしょう、それは最も簡潔で、あなたが意味するものを正確に表しています。

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

ヒューズ2つのマップ:

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

置き換えconcatMapconcat . map

あなたが Data.Monoidに依存したくなかった場合

オリジナルのコードを次のようにしかし、あなたは書き換えることができ

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

これで完了です。

編集: aaaaこれは@Jan Christiansenの答えとまったく同じです。しかたがない!

+0

ところで、ハスケルに関する質問に答えるまでどのくらい時間がかかるのですか?私は、ハスケルのすべての質問の90%がほぼ即座に答えられるという印象を受けています。これは答えの質については何も言いませんが、私の意見では彼らもかなり高い品質を持っています。 –

+2

@JanChristiansen:もしあなたが望むなら、スタック交換データエクスプローラを使ってそれに答えることができます。私は非常におおよその近似を行い(明らかな異常値をフィルタリングし、自己解答を無視する)、典型的な(すなわち中央値の)時間は、最初の回答が投稿されるまで約20分であった。 –