2つのリストがある場合、[a, b]
および[c, d]
、次の結果を取得したい:
[(a,c), (a,d), (b,c), (b,d)]
Haskellでこれを行うにはどうすればよいですか?このための組み込み関数はありますか、それとも自分で実装する必要がありますか?
[ (x,y) | x<-[a,b], y<-[c,d] ]
これ以上の説明は必要ありませんね。
ずっと応用スタイル!
λ> :m + Control.Applicative
λ> (,) <$> ['a','b'] <*> ['c','d']
[('a','c'),('a','d'),('b','c'),('b','d')]
(例に近づけるために、上記のString
シンタックスシュガーは避けました。)
詳細については、(,)
は、2つの引数を取り、それらからペアを作成する関数の特別な構文です。
λ> :t (,)
(,) :: a -> b -> (a, b)
編集: 彼のコメント の leftaroundabout で指摘されているように、liftA2
を使用することもできます。
λ> :m + Control.Applicative
λ> let combine = liftA2 (,)
λ> combine "ab" "cd"
[('a','c'),('a','d'),('b','c'),('b','d')]
命令型擬似コードでこれをどのように行うことができますか?
_for each element x in [a,b]:
for each element y in [c,d]:
produce (x,y)
_
Haskellでは、これは次のように書かれています
_outerProduct xs ys =
do
x <- xs -- for each x drawn from xs:
y <- ys -- for each y drawn from ys:
return (x,y) -- produce the (x,y) pair
_
(コメントに続いてleftaroundabout)これはもちろん非常にどのように近いか _liftM2
_ モナドコンビネータが定義されているので、実際には
_outerProduct = liftM2 (,)
_
これはliftA2 (,)
と同じであり、リスト内包表記、concatMap
関数、_>>=
_、_<$>
_、および_<*>
_に関するさまざまな書き直しです。演算子。
概念的には、これはApplicative
のものですが、これはPairing
という名前の方が適切です。これは、2つの「コンテナ」の要素のペアリングであるためです。 ⁄「キャリア」⁄whateverは、まさにApplicativeFunctorの目的です。 Haskellのdo
表記はモナドでは機能し、(まだ) Applicativeでは では機能しないのは偶然です。
ある意味でcompile-timeネストされたループareApplicative ⁄ Pairing functors;モナドは、「外部」列挙によって生成された値に応じて、ネストされたループをその場で作成する機能を追加します。
最も直感的なのはリスト内包表記の使用ですが、他のアプローチには適用可能なファンクターの使用が含まれます。
_(,) <$> [1,2,3] <*> [4,5,6]
_
では、これは何をするのでしょうか?
_(,) :: a -> b -> (a, b)
_は2つの引数を取り、タプルを返すことに注意してください。
_<$>
_は実際にはfmap、_(<$>) :: Functor f => (a -> b) -> f a -> f b
_関数を取り、それを持ち上げます。この場合、_(,)
_を取り、リストで機能するように持ち上げます。したがって、let x = (,) <$> [1,2]
はx :: [b -> (Integer, b)]
を生成します。これは、b
を取り、1つの固定引数(Integer、b)を持つタプルを返す関数のリストです。最後に、_<*>
_を使用してそれを適用し、すべての組み合わせを生成します。
リスト内包表記を使用する:
s = [a,b]
s' = [c,d]
all_combinations = [(x,y) | x <- s, y <- s']