web-dev-qa-db-ja.com

Haskellの2つのリストの要素のすべての組み合わせ

2つのリストがある場合、[a, b]および[c, d]、次の結果を取得したい:

[(a,c), (a,d), (b,c), (b,d)]

Haskellでこれを行うにはどうすればよいですか?このための組み込み関数はありますか、それとも自分で実装する必要がありますか?

17
Ben
[ (x,y) | x<-[a,b], y<-[c,d] ]

これ以上の説明は必要ありませんね。

28
leftaroundabout

ずっと応用スタイル!

λ> :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')]
15
jub0bs

命令型擬似コードでこれをどのように行うことができますか?

_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;モナドは、「外部」列挙によって生成された値に応じて、ネストされたループをその場で作成する機能を追加します。

9
Will Ness

最も直感的なのはリスト内包表記の使用ですが、他のアプローチには適用可能なファンクターの使用が含まれます。

_(,) <$> [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)を持つタプルを返す関数のリストです。最後に、_<*>_を使用してそれを適用し、すべての組み合わせを生成します。

8
concept3d

リスト内包表記を使用する:

s = [a,b]
s' = [c,d]

all_combinations = [(x,y) | x <- s, y <- s']
6