2013-02-10 84 views
5

從書中Learn You a Haskell For Great Good偏函數的相關章節包含以下代碼:什麼是這些Haskell高階函數的Python等價物?

multThree :: (Num a) => a -> a -> a -> a 
multThree x y z = x * y * z 

ghci> let multTwoWithNine = multThree 9 
ghci> multTwoWithNine 2 3 
54 
ghci> let multWithEighteen = multTwoWithNine 2 
ghci> multWithEighteen 10 
180 

我目前在Python中functools庫中播放,並設法複製使用它的職能的行爲。

from functools import partial 

def multThree(x,y,z): 
    return x * y * z 

>>> multTwoWithNine = partial(multThree,9) 
>>> multTwoWithNine(2,3) 
>>> multWithEighteen = partial(multTwoWithNine,2) 
>>> multWithEighteen(10) 
180 

有一件事我現在想要做的就是看能不能從同一本書章節複製一些比較有意思的高階功能,如:

zipWith' :: (a -> b -> c) -> [a] -> [b] -> [c] 
zipWith' _ [] _ = [] 
zipWith' _ _ [] = [] 
zipWith' f (x:xs) (y:ys) = f x y : zipWith' f xs ys 

不過,我米不知道如何做到這一點,或者如果partial()甚至在這裏有用。

+1

您應該編輯和修復你的職責,確保他們都是語法正確。例如,你的第一個問題就是缺少它的論點。 – 2013-02-10 04:34:51

+2

從技術上講,你必須在任何轉換中使用'partial',因爲所有的Haskell函數都會自動執行curried,而'partial'模擬curried函數必須部分應用的能力。或者您可以將python版本編寫爲curried函數,但是您必須將它們稱爲「foo(a)(b)(c)'。 – Wes 2013-02-10 04:57:33

+2

小調:你想要「部分應用功能」而不是「部分功能」。 – 2013-02-10 09:35:21

回答

5

Python的內置map功能的行爲就像Haskell的zipWith

>>> def add(x,y): return x + y 
... 
>>> map(add,[1,2,3],[10,20,30]) 
[11, 22, 33] 
+1

地圖是內置的而不是在庫中定義的? – 2013-02-10 04:36:17

+0

是的,地圖和添加內置於Python中的函數 – 2013-02-10 04:53:57

+1

我想我希望解釋爲什麼它是(必須是?)內置的。 – 2013-02-10 05:28:56

0

這Python代碼的作用類似於zipWith'功能你給了:

def zip_with(f, l1, l2): 
    if len(l1) == 0 or len(l2) == 0: 
     return [] 
    else: 
     return [f(l1[0], l2[0])] + zip_with(f, l1[1:], l2[1:]) 

但是,與Haskell函數相比,此函數有一些缺點。首先,它看起來不太好,因爲Python沒有模式匹配語法;我們必須改用len,[0][1:]。第二個是Python函數不會以任何方式使用懶惰評估,所以即使它可能早早停止,它也會一直遍歷整個列表。第三個是該函數爲結果列表的每個元素調用一次,並且Python的遞歸限制約爲1000(或者恰好?)1,000,所以如果輸出列表長度大於1,000個元素,此函數將引發異常。

第二和第三個問題可以使用生成器來解決。

+0

你也可以使用'[f(l1.pop(),l2。pop())] + zip_with(f,l1,l2)''因此不需要醜陋的'[0]'或'[1:]' – ThatWeirdo 2016-11-13 20:07:11

0

這是一個很好的選擇使用內置zip功能和列表理解:

>>> zip_with = lambda fn, la, lb: [fn(a, b) for (a, b) in zip(la, lb)] 

>>> add2 = lambda x,y: x+y 
>>> zip_with(add2, range(10), range(1,11)) 
[1, 3, 5, 7, 9, 11, 13, 15, 17, 19]