2015-08-19 14 views
13

otrzymuje dwie listy, [a, b] i [c, d], Chciałbym uzyskać następujący wynik:Wszystkie kombinacje elementów dwóch list w Haskell

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

Jak mogę to zrobić w Haskell? Czy jest do tego wbudowana funkcja, czy też powinienem ją sam wdrożyć?

+3

Gdy typy '[a, b]' i '[c, d]' są równe, możesz napisać 'sekwencję [[a, b], [c, d]]'. – user3237465

Odpowiedz

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

To naprawdę nie wymaga żadnych dodatkowych wyjaśnień, prawda?

+0

Nie, to prawda, dzięki; Zastanawiałem się tylko, czy istnieje wbudowany, który to robi; coś w rodzaju "combo xs ys", które daje taki sam wynik. – Ben

+10

@Ben: 'combos = liftA2 (,)', co jest w zasadzie równoznaczne z sugestią Jubobs'a. – leftaroundabout

+0

@leftaroundabout bardzo ładne wykorzystanie aplikacji! –

5

użycie Lista Rozumienie:

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

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

Jak można zrobić to w bezwzględnej Pseudokod?

for each element x in [a,b]: 
    for each element y in [c,d]: 
     produce (x,y) 

W Haskell, to jest napisane jak

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 

(po komentarzach leftaroundabout) To oczywiście niezwykle blisko jak liftM2 monadycznego syntezatora jest określona, ​​więc w fakt:

outerProduct = liftM2 (,) 

, który jest taki sam jak liftA2 (,), i jego różnych ponownych zapisów w zakresie zrozumienia list, operatorów concatMap, operatorów >>=, <$> i <*>.

Konceptualnie choć jest to rzeczy z Applicative – które byłyby lepiej nazwie jak Pairing, – ponieważ parowanie się z elementów dwóch „kontenery” ⁄ „nośnikami” ⁄ cokolwiek właśnie aplikacyjnych funktora jest o . Tak się składa, że ​​notacja Haskella o nazwie do działa dla monad, a nie (jeszcze) for applicatives.

w pewnym sensie kompilacji zagnieżdżonych pętli ⁄ aplikacyjnych Parowanie funktory; Monady dodają możliwość tworzenia zagnieżdżonych pętli w locie, w zależności od wartości generowanych przez "zewnętrzne" wyliczenie.

+4

Warto zauważyć, że notowania "do" i rozumienia list są właściwie zarówno syntaktycznym cukrem dla tych samych monadycznych kombinatorów, a mianowicie "[a, b] >> = \ x -> [c, d] >> = \ y - > return (x, y) '. – leftaroundabout

+0

@leftaroundabout, to po prostu nieprawda. Zrozumienie list nie ma jednego, ale dwa zabiegi w desugarer, z których żaden nie daje '>> =' lub 'return'. – dfeuer

+0

Rzeczywiście; należy włączyć '-XMonadComprehensions', aby lista mogła w rzeczywistości używać' >> = 'i' return'. Bez tego rozszerzenia używają równoważnych funkcji specyficznych dla listy. – leftaroundabout

14

Styl aplikacyjny do końca!

λ> :m + Control.Applicative 
λ> (,) <$> ['a','b'] <*> ['c','d'] 
[('a','c'),('a','d'),('b','c'),('b','d')] 

(mam unikał dowolny String cukier syntaktyczny powyżej, aby pozostać blisko swojej przykład.)

Aby uzyskać więcej informacji, (,) jest specjalna składnia dla funkcji, które ma dwa argumenty i sprawia, że ​​parę z nich:

λ> :t (,) 
(,) :: a -> b -> (a, b) 

Edit: Jak zauważył leftaroundabout w his comment, można również użyć liftA2:

λ> :m + Control.Applicative 
λ> let combine = liftA2 (,) 
λ> combine "ab" "cd" 
[('a','c'),('a','d'),('b','c'),('b','d')] 
7

najbardziej inuitive będzie za pomocą listy ze zrozumieniem, inne aproaches obejmować korzystanie APPLICAT ive funktory:

(,) <$> [1,2,3] <*> [4,5,6] 

Co to oznacza?

Pamiętaj, że (,) :: a -> b -> (a, b) Wykonuje dwa argumenty i zwraca krotkę.

jest acutally fmap, (<$>) :: Functor f => (a -> b) -> f a -> f b To zajmuje funkcję i podnieś ją. W takim przypadku zajmuje on (,) i podnosi go do listy roboczej. Tak więc let x = (,) <$> [1,2] wygenerowałaby x :: [b -> (Integer, b)], która jest listą funkcji, która zajmuje b i zwraca krotkę z jednym ustalonym argumentem (Integer, b). Na koniec stosujemy go przy użyciu <*>, aby wygenerować wszystkie kombinacje.

Powiązane problemy