簡體   English   中英

Haskell: Uncurry, Curry, 組合

[英]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) -> ccurry :: ((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 -> ...

請注意,上面是一個柯里化函數,將xy作為單獨的參數。 然后我們有:

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組合子是多余的。 讓我們試着用SK組合子寫下來。 主要思想是 I 的唯一參數應作為K的第一個參數傳遞,其第二個參數已被占用。 這正是S組合器所做的:如果我們將K作為S的第一個參數傳遞,我們將讓它返回S的第三個參數:

SKbc = Kc(bc) = c

我們已經證明( K*ab = b ):

K* = SK

因此,我們只需要選擇第二個參數: KS都可以:

I = SKK = SKS

可以看出,組合子I對應於id 組合子K對應於 const; 和組合子S對應於(<*>) :: (e -> a -> b) -> (e -> a) -> e -> b

I = SKK對應於const <*> const :: a -> a 由於鍵入,我們的其他結果( I = SKSK* = 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM