2013-09-27 120 views
1

假設我們有兩個函數(a -> b -> c)。我想要有一個函數,它適用於ab將給出d,從c合併指定的函數(c -> c -> d)。我想出了用箭頭此解決方案:結合兩個curried函數

combine :: (a -> b -> c) -> (a -> b -> c) -> (c -> c -> d) -> (a -> b -> d) 
combine f g op = ((uncurry op) .) . (uncurry (&&&)) . (f &&& g) 

有沒有一種方式,更優雅的方式來做到這一點,或者概括它是適用於功能具有更大的元數(例如(a -> b -> c -> d) -> (a -> b -> c -> d) -> (d -> d -> e) -> (a -> b -> c -> e))?

回答

7

不要害怕明確。對我來說這是很容易閱讀:

combine :: (a -> b -> c) -> (a -> b -> c) -> (c -> c -> d) -> (a -> b -> d) 
combine f g op = \a b -> op (f a b) (g a b) 

不看任何醜陋更多arities:

combine3 f g op = \a b c -> op (f a b c) (g a b c) 
+1

我認爲用'op'作爲中綴會更好:''''''''''''''''我懷疑有些人可能會不同意;其中一部分是我的編輯突出顯示不同的事情,這使得它更容易閱讀。 –

+0

非常完美,謝謝!當你已經看到答案時,它總是很容易:) –

3

雖然我同意明確拉姆達可能是去這裏的路上,有替代品二進制fg。對於一元fg,解決方案是基本的。

combine f g op = liftM2 op f g 

二進制fg,我們可以讓他們通過一元他們uncurrying,然後採用相同的解決方案!這使得二進制版本

combine2 f g op = curry $ liftM2 op (uncurry f) (uncurry g) 

我只是把它放在那裏作爲替代。

+0

這太棒了。在操作員上使用'liftM2'來利用函數'( - > r)'作爲單子。輝煌! – pyrospade