2011-10-23 2 views
5

Załóżmy, że chcemy uzyskać map nad kolekcją, ale zbieramy wyniki zmapowanej funkcji tylko wtedy, gdy odwzorowana wartość spełnia określone kryteria. Jestem obecnie robi to jako takie:IDENTYFIKACJA Haskella dla mapy "selektywnej"

func = foldl (\acc x, -> (maybeGrab x):acc) [] 


maybeGrab a 
    | a > 5 = [someFunc a] 
    | otherwise = [] 

Chociaż to działa, jestem pewien, że jest bardziej idiomatyczne „prawo/common/bardziej rozpoznawalny” sposób to zrobić.

+3

Czy filtr nie spełnia wymagań? A może mapMaybe z Data.Maybe? –

+1

@JeffFoster: 'mapMaybe' jest poprawną odpowiedzią. Powinieneś opublikować ją jako odpowiedź, abyśmy mogli ją zatwierdzić. – Chuck

+0

Tak, Jeff ma rację. Najbliższa odpowiedź ma mój głos. –

Odpowiedz

10
mapMaybe :: (a -> Maybe b) -> [a] -> [b] 

mapMaybe z pakietu Data.Maybe wygląda tak, jak robi to zadanie. Dokumentacja mówi:

Funkcja mapMaybe jest wersją mapy, która może wyrzucać elementy. W szczególności argument funkcjonalny zwraca coś z rodzaju Może b. Jeśli nie ma nic, żaden element nie jest dodawany do listy wyników. Jeśli to po prostu Just b, to b jest zawarty na liście wyników.

0

Hmm. To zdecydowanie wydaje się być miejscem, w którym spasowanie jest w porządku. Co powiedzieć:

func = foldl (\acc x -> let a = g x in if a > 5 then a:acc else acc) [] 

Tutaj g to funkcja, którą próbujesz zamapować na listę.

Nie mogę wymyślić żadnej funkcji, która natywnie łączy mapę i filtr bez składania.

[EDIT]

Och, podobno jest tam mapMaybe. Nigdy wcześniej tego nie używano. Poprawiono mnie. Ha, ucz się czegoś przez cały czas.

+0

Eek 'foldl'! Właśnie straciłeś możliwość przesyłania strumieniowego tej listy. – luqui

+0

Cóż, nie ma takiego, który jest * lepszy * między foldl i foldr. Gdyby przetwarzał dużą listę, nieskończoną, zmniejszyłby przestrzeń nad głową z zawijaniem. Jeśli jednak wspomniałeś, że przesyłał strumieniowo lub pracował z nieskończoną listą, foldr byłby jedynym sposobem, w jaki mógłby to zrobić. –

+0

Nie. Narzut przestrzeni w 'foldl'' to Theta (lista wyjściowa). Spaceoverhead dla 'foldr' to O (lista wyjściowa). 'foldl'' wykonuje całe obliczenie przed powrotem,' foldr' dziedziczy strukturę obliczeniową swojego użytkownika. 'foldl'' jest przegranym, gdy typ wyjściowy nie jest płaski, jak w tym przypadku. – luqui

5

Osobiście zrobiłbym to w dwóch etapach: po pierwsze, wyeliminuj wartości, których nie obchodzi, a następnie mapuj.

func = map someFunc . filter (>5) 

ten może być również wyrażony ładnie postaci listy zrozumieniem.

func xs = [someFunc x | x <- xs, x > 5] 
+0

Jeśli żądany filtr zależy od * wytworzonej wartości *, można oczywiście odwrócić kolejność: 'filter cond. mapować someFunc'. –