2013-10-06 77 views
5

雖然在Haskell寫一些lambda函數,我本來寫類似的功能:Haskell - Lambda微積分等效語法?

tru = \t f -> t 
fls = \t f -> f 

不過,我很快就從例子中注意到網上,這樣的功能是經常這樣寫:

tru = \t -> \f -> t 
fls = \t -> \f -> f 

具體,傳遞給函數的每個項目都有自己的\->而不是上面的。當檢查它們的類型時,它們看起來是相同的。我的問題是,它們是否相同或它們在某種程度上有所不同?而不僅僅是這兩個功能,但它是否對一般功能有所幫助?非常感謝!

回答

14

他們是一樣的,哈斯克爾自動curries事情保持語法很好。以下都是等價的**

foo a b = (a, b) 
foo a = \b -> (a, b) 
foo = \a b -> (a, b) 
foo = \a -> \b -> (a, b) 
-- Or we can simply eta convert leaving 
foo = (,) 

如果你想成爲習慣,比較喜歡第一個或最後一個。引入不必要的lambda表達式對於教捲曲是很好的,但是在實際的代碼中只是增加了語法混亂。

然而,在原料演算(不哈斯克爾)與

\a -> \b -> a b 

最手動咖喱因爲人們不要用手寫了很多演算的,當他們這樣做,他們往往堅持unsugared演算保持事情很簡單。

**以modomo單態限制,它不會影響你與類型簽名反正。

+0

我應該注意的是,雖然我更喜歡大多數事物的第一個或最後一個,但第二個也是有時候的替代方案,例如定義運算符時。你可以想象做一些像'f。 g = \ x - > f(g x)'。 – kqr

+0

這是正確的,但轉型不是曲解;它只是語法糖。 Currying將'(a,b) - > c'轉換爲'a - >(b - > c)'(因此'curry ::((a,b) - > c) - > a - > b - > c ')。確實,這個符號的設計是爲了簡化編寫curried函數。 (這可能是你想說的,但我認爲這值得明確。) –

6

雖然,正如jozefg所說,它們本身是等價的,但它們可能在與局部變量綁定結合時導致不同的執行行爲。考慮

f, f' :: Int -> Int -> Int 

與兩個定義

f a x = μ*x 
where μ = sum [1..a] 

f' a = \x -> μ*x 
where μ = sum [1..a] 

這些看起來確實相當的,而且肯定會始終產生相同的結果。

GHCi,版本7.6.2:http://www.haskell.org/ghc/:?尋求幫助
...
[1的1]編譯主(def0.hs,解釋)
好吧,模塊加載:主。
*主要>總和$地圖(F 10000)[1..10000]
25005000.25億
*主要>總和$映射(F」 10000)[1..10000]
25005000.25億

但是,如果您自己嘗試此操作,則會注意到f需要相當長的時間,而f'會立即得到結果。原因是f'是以提示GHC編譯它的形式編寫的,因此在開始將它映射到列表之前對f' 10000進行了評估。在該步驟中,計算值μ並將其存儲在關閉(f' 10000)中。另一方面,f被簡單地理解爲「兩個變量的一個函數」; (f 10000)僅作爲包含參數10000的閉包存儲,而μ根本不計算在內。只有當map(f 10000)應用於列表中的每個元素時,纔會計算整個sum [1..a],對於[1..10000]中的每個元素需要一些時間。由於f',這是不必要的,因爲μ是預先計算的。

原則上,共同子表達式消除是GHC能夠自行完成的優化,所以即使使用像f這樣的定義,您也可能有時會獲得良好的性能。但是你不能指望它。