2011-07-06 19 views
8

Chcę zrobić coś dość prostego; Używam operatora (++) z Data.Map insertWith, i działa dobrze, ale chcę wyeliminować duplikaty w utworzonej wartości, więc chcesz skomponować go z nub.kompozycja z dyndycznym operatorem?

Próbowałem (nub (++)), (nub $ (++)), (n. (++)), wszystko bezskutecznie, ponieważ typ (++) nie pasuje do oczekiwany typ nub ([a]).

Mogę oczywiście zdefiniować funkcję pomocniczą lub lambdę, ale myślę, że prawdopodobnie istnieje kompozycja, która byłaby wyraźniejsza.

Wskazówki proszę!

Odpowiedz

10

Możesz napisać to jako

((nub .) .) (++) 

Przykład:

Prelude Data.List> ((nub .) .) (++) [1,2,3] [3,4,5] 
[1,2,3,4,5] 

W ogóle, masz

(f .) g x = f (g x) 
((f .) .) g x y = f (g x y) 
(((f .) .) .) g x y z = f (g x y z) 
((((f .) .) .) .) g x y z v = f (g x y z v) 
... 

Oto wyprowadzenie tej tożsamości dla ((nub .) .):

(f . g) x = f (g x) 

(nub .) :: Eq a1 => (a -> [a1]) -> a -> [a1] 
(nub .) = \g x -> (nub (g x)) 

((nub .) .) :: Eq a2 => (a -> a1 -> [a2]) -> a -> a1 -> [a2] 
((nub .) .) = ((\g x -> (nub (g x))) .) = (\g' x' -> (\g x -> (nub (g x))) (g' x')) 
      = \g' x' x -> (nub ((g' x') x)) 

Jest nice article na ten temat (i pokrewnych) idiomów, ale to w rosyjskiej :-(

+0

Bardzo ładne, dzięki - za odpowiedź i wyprowadzenie. (Twoja ostatnia linia wyprowadzania wygląda tak, jakby była w języku rosyjskim !?) – guthrie

+0

taka sama jak '(nub.). (++) ' – user102008

1

Można użyć nieco śmieszne patrząc (.).(.) COMBINATOR:

Prelude> :set -XNoMonomorphismRestriction 
Prelude> :m + Data.List 
Prelude Data.List> let f = ((.).(.)) nub (++) 
Prelude Data.List> :t f 
f :: Eq a => [a] -> [a] -> [a] 
Prelude Data.List> f "ab" "ac" 
"abc" 

To prawdopodobnie będzie bardziej czytelny po prostu użyć lambda lub źródła zewnętrznego funkcji w where -clause, choć.

6

Co chcesz wydaje się być kompozycją funkcji podwójnych i pojedynczych, jak to:

compose :: (c -> d) -> (a -> b -> c) -> (a -> b -> d) 
compose unary binary a b = unary (binary a b) 

I poprosić o punkcie wolne wersji (nie wspominając o a i b zmiennych). Spróbujmy je wyeliminować jeden po drugim. Zaczniemy b, wykorzystując fakt, że f (g x) = f . g:

compose unary binary a = unary . binary a 

a jest obok. Załóżmy desugar pierwszy wyraz:

compose unary binary a = ((.) unary) (binary a) 

I zastosować tę samą zasadę kompozycji znowu:

compose unary binary = ((.) unary) . binary 

ten można dodatkowo zapisać jako:

compose unary = (.) ((.) unary) 

lub nawet

compose = (.) . (.) 

Tutaj, każdy (.) "usuwa" argument z funkcji binarnej i potrzebujesz dwóch z nich, ponieważ funkcja jest binarna. Ten idiom jest bardzo użyteczny, gdy jest uogólniony dla dowolnego funktora: fmap . fmap (zauważ, że fmap jest równoważny ., gdy funkcja jest postrzegana jako funktor). Pozwala to na 'taśmy' każdy funktora off, na przykład można napisać:

incrementResultsOfEveryFunctionInTwoDimentionalList :: [[String -> Integer]] -> [[String -> Integer]] 
incrementResultsOfEveryFunctionInTwoDimentionalList = fmap . fmap . fmap $ (+1) 

Tak, Twój wynik staje:

(fmap . fmap) nub (++) 

Edit:

Chyba znalazłem odpowiedź, którą mój mózg próbował odtworzyć: Haskell function composition operator of type (c→d) → (a→b→c) → (a→b→d)

+0

Dzięki, lubię swoje pochodzenie i logiczne. Teraz pamiętam, że wcześniej to wszystko wymyśliłem dla innej aplikacji i zapomniałem o tym. Myślę, że wygodnie jest myśleć o każdej aplikacji "." jako punkt wstawienia argumentu. – guthrie

1

Nie sądzę, że operator kompozycji, który chcesz, istnieje jako jedna funkcja jon w dowolnej standardowej bibliotece. Najkrótszym sposobem na jego zapisanie jest prawdopodobnie ((.).(.)).Używając definicji Functor dla ((->) t), możesz również zapisać ją jako fmap . fmap lub, jeśli wolisz, fmap fmap fmap.

Wszystkie powyższe są dość zagadkowe, ale idiom jest na tyle powszechny, że wiele osób rozpoznaje to, co robisz.

przy okazji, może chcesz uniknąć wywoływania funkcji dwóch argumentów „dwójkowym” w Haskell, bo jeśli przedłużyć ten terminologię do funkcji jednoargumentowych masz zamiar naprawdę mylić ludzi.

Zobacz także this question w celu omówienia pokrewnej dyskusji.

Możesz również znaleźć lots of combinators with very intuitive names w tej bibliotece.

+3

Bardzo mi się podobało komentarz diadyczny :-) – luqui

+1

@luqui: Niestety innym powszechnie używanym terminem dla funkcji 2-ary jest "binarny", który sam jest przeładowany żargonem, ale jest bardziej prawdopodobne, że będzie jasny z kontekstu. Używanie "monadycznych" zamiast "unarnych" jest tylko błaganiem o masowe zamieszanie, rozpacz, niepokoje społeczne i ogólne niedogodności. –

+0

@all - dzięki za wyjaśnienia (?!) - Postaram się w ogóle unikać mówienia o argumentach, ponieważ wydają się ... argumentacyjne. :-) – guthrie

Powiązane problemy