2011-07-06 33 views
8

我想做一些相當簡單的事情; 我使用運算符(++)與Data.Map insertWith,它工作正常,但我想消除所創建的值中的重複項,所以想要使用nub進行組合。 (++)的類型不匹配(nub(++)),(nub(++)預期的結點類型([a])。與二元運算符的組合?

我當然可以定義一個輔助函數或lambda,但我認爲可能有一個更清晰的組合。

提示請!

回答

10

你可以寫爲

((nub .) .) (++) 

例子:

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

在一般情況下,你必須

(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) 
... 

下面是這個身份爲((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)) 

有一個nice article這個(以及相關的)的成語,但它在俄羅斯:-(

+0

非常好,謝謝 - 答案和推導。 (你推斷的最後一行看起來好像可能是俄文!?) – guthrie

+0

與'(nub。)相同。 (++)' – user102008

1

可以使用有點古怪的(.).(.)組合子:

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" 

它可能會是更可讀的,只是使用lambda或一個輔助功能在where -clause,雖然。

6

你想要什麼似乎是二元和一元函數組合,像這樣:

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

你問一個免費的點版本(無ab變量提)。讓我們試着逐個消除它們。我們將與b開始,用事實f (g x) = f . g

compose unary binary a = unary . binary a 

a旁邊。讓我們desugar表達第一:

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

,然後再次申請相同的組成規則:

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

這可以進一步寫成:

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

或者甚至

compose = (.) . (.) 

在這裏,每個(.)'去掉'二元函數的參數,因爲函數是二進制的,所以你需要兩個參數。當爲任何仿函數推廣時,該成語非常有用:fmap . fmap(注意,fmap等於.,當函數被視爲仿函數時)。這可以讓你 '脫光' 任何函子了,比如你可以這樣寫:

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

所以,你的結果變成:

(fmap . fmap) nub (++) 

編輯:

我想我已經找到我的大腦試圖重現的答案:Haskell function composition operator of type (c→d) → (a→b→c) → (a→b→d)

+0

謝謝你,我喜歡你的推導和邏輯。我現在記得我之前已經想到了另外一個應用程序,並且忘記了它。我認爲考慮「。」的每個應用可能是方便的。作爲參數插入點。 – guthrie

1

我不認爲你想要的組合運算符是作爲一個函數存在的離子在任何標準庫中。寫它的最簡單的方法可能是((.).(.))。使用((->) t)Functor定義,您也可以將其編寫爲fmap . fmap或者如果您更喜歡fmap fmap fmap

以上所有內容都很神祕,但這個成語很常見,所以很多人會認識你在做什麼。順便說一句,你可能希望避免在Haskell中調用兩個參數「二進制」的函數,因爲如果你將這個術語擴展到一個參數的函數,你會真的迷惑人。

另請參閱this question的一些相關討論。

您還可以在此圖書館中找到lots of combinators with very intuitive names

+3

Loved the dyadic comment :-) – luqui

+1

@luqui:可悲的是,二元函數的另一個常見術語是「二元」,它本身是超載的行話,但更容易從上下文中清楚。使用「一元」而不是「一元」只是乞求羣體混亂,絕望,內亂和一般不便。 –

+0

@all - 謝謝你的澄清(?!) - 我會盡量避免談論論證,因爲他們看起來是......論證性的。 :-) – guthrie