![](/img/trans.png)
[英]How do you define and use curry and uncurry (Prelude functions) in Haskell?
[英]Haskell: Uncurry, Curry, composition
當我輸入以下內容時,我無法理解編譯器的作用:
(curry . uncurry) (+) 1 2
在我理解之后,編譯器首先使用 uncurry,這意味着會發生錯誤,因為 uncurry 函數需要這樣的輸入:
(curry . uncurry) (+) (1,2)
但顯然第一個是對的。 我不明白為什么。
編譯器在評估這個時到底采取了哪些步驟?
另一個主題包括問題:為什么
(uncurry . curry) (+) (1,2)
不起作用?
在我理解之后,編譯器采用了 uncurry。
不,它與(curry . uncurry)
如果我們評估(curry . uncurry)
函數,我們會看到它的縮寫:
\x -> curry (uncurry x)
所以(curry . uncurry) (+) 1 2
函數的縮寫是:
(\x -> curry (uncurry x)) (+) 1 2
或因此:
(curry (uncurry (+))) 1 2
和uncurry :: (a -> b -> c) -> (a, b) -> c
和curry :: ((a, b) -> c) -> a -> b -> c
因此轉換一個函數. 因此,這意味着uncurry (+)
確實需要一個 2 元組:
uncurry (+) :: Num a => (a, a) -> a
但是現在通過curry
函數傳遞這個函數:
curry (uncurry (+)) :: Num a => a -> a -> a
所以curry
函數會撤銷uncurry
對(+)
函數所做的轉換。 因此,這意味着curry (uncurry (+))
與(+)
相同,因此:
(curry (uncurry (+))) 1 2
相當於:
(+) 1 2
這因此相當於3
。
curry . uncurry
curry . uncurry
並不完全等同於id
,因為它具有以下類型:
curry . uncurry :: (a -> b -> c) -> a -> b -> c
因此,這意味着它將函數限制為a -> (b -> c)
類型a -> (b -> c)
函數。
您的表達式解析為
(((curry . uncurry) (+)) 1) 2
因此,它構建函數(curry . uncurry) (+)
並將其應用於1
,然后將生成的函數應用於2
。
因此,我們從(curry . uncurry) (+)
,意思是curry (uncurry (+))
。 為簡單起見假設(+)
實現為
(+) = \x y -> ...
請注意,上面是一個柯里化函數,將x
和y
作為單獨的參數。 然后我們有:
curry (uncurry (+))
= { definition + }
curry (uncurry (\x y -> ...)) -- note the separate arguments
= { definition uncurry }
curry (\(x, y) -> ...) -- only one pair argument
= { definition curry }
(\x y -> ...) -- back to two arguments
= { definition + }
(+)
上面, uncurry
將函數+
轉換為一個接受一對參數而不是兩個參數的函數。 這種轉換被curry
反轉,它將 pair 參數分成兩個單獨的參數。
確實, curry . uncurry
curry . uncurry
是二進制curry . uncurry
函數的恆等變換,因為它應用了變換及其逆。 因此,它對結果或所涉及函數的類型沒有影響。
我們得出結論,您的表達式等效於((+) 1) 2
,其計算結果為3
。
這個問題得到了很好的答案,但我想添加一個關於curry . uncurry
的注釋curry . uncurry
curry . uncurry
。
您可能聽說過SKI
演算。 如果你還沒有,這是一個微積分,我們使用 3 個組合子:
Sabc = ac(bc)
Kab = a
Ia = a
眾所周知,圖靈完備。
此外, I
組合子是多余的。 讓我們試着用S
和K
組合子寫下來。 主要思想是 I 的唯一參數應作為K
的第一個參數傳遞,其第二個參數已被占用。 這正是S
組合器所做的:如果我們將K
作為S
的第一個參數傳遞,我們將讓它返回S
的第三個參數:
SKbc = Kc(bc) = c
我們已經證明( K*ab = b
):
K* = SK
因此,我們只需要選擇第二個參數: K
和S
都可以:
I = SKK = SKS
可以看出,組合子I
對應於id
; 組合子K
對應於 const; 和組合子S
對應於(<*>) :: (e -> a -> b) -> (e -> a) -> e -> b
。
I = SKK
對應於const <*> const :: a -> a
。 由於鍵入,我們的其他結果( I = SKS
和K* = SK
)在 Haskell 中不成立:
GHCi> :t (<*>) const (<*>) {- id -}
(<*>) const (<*>) {- id -}
:: Applicative f => f (a -> b) -> f (a -> b)
GHCi> :t (const <*>) {- flip const -}
(const <*>) {- flip const -} :: (b -> a) -> b -> b
可以看出,我們的實現充當了他們領域中所需的功能,但我們縮小了領域。
如果我們指定(<*>) const (<*>)
給讀者,我們就會得到你寫成curry . uncurry
的函數curry . uncurry
curry . uncurry
- 函數的id
。
curry . uncurry
另一種工作方式curry . uncurry
curry . uncurry
是($)
:
f $ x = f x
($) f x = f x
($) f = f
($) = id
你發現的函數很有趣——尋找其他類似的函數可能是一個很好的練習(我不知道那里是否還有其他值得注意的函數)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.