Lambda演算與科里化 Currying

2021-05-09 11:39:25 字數 2818 閱讀 4555

lambda演算與科里化(currying)

lambda

演算

早在現代計算機問世以前,lambda演算(λ演算)已經由圖靈的老師阿隆佐·邱奇(alonzo church)引入。這種演算可以用來清晰地定義什麼是乙個可計算函式。它包括一條變換規則(變數替換)和一條函式定義方式,lambda 演算的通用性在於任何乙個可計算函式都能用這種形式來表達和求值。因而,它等價於後來提出的圖靈機。lambda 演算對函式式程式語言有巨大的影響,比如 lisp 語言、ml 語言和 haskell 語言(後面還會提到haskell這個人)。

簡介

在lambda演算中的每乙個表示式都代表乙個單輸入(單引數)的函式,函式的輸出(值)仍然是乙個這樣的函式。例如乙個簡單的增值函式 f(x) = x + 1在lambda演算中我們可以這樣表示:

λx. x + 1。這裡的x叫做這個lambda表示式的引數。相應的f(2)可以表示為:(

λx. x + 1)2。特別的這裡的引數也可以是乙個類似的函式,在lambda演算中所有函式都是匿名函式,

它們既可以是其他函式的返回值也可以是引數,下面來看乙個稍微複雜一點的例子: (λ f. f 3)(λ x. x+1) 。這個表示式的意思是說要將f 3這個行為應用到我們先前定義的函式λ x. x+1上去。該表示式等價於 (λ x. x + 2) 3 = 3+2。

lambda演算的形式化定義

lambda

演算的過程是由若干個lambda表示式構成的。乙個lambda表示式包含了一組變數v1, v2, …, vn,以及抽象符號『λ』和『( )』。這些lambda表示式的集合λ遞迴地定義如下:

如果 x 是乙個變數, 則x ∈ λ

如果 x 是乙個變數且 m ∈ λ, 則 (λx.m) ∈ λ

如果m, n ∈ λ, 則(m n) ∈ λ

科里化(

currying

科里化的概念最早由**數學家moses schönfinkel引入,而後由著名的數理邏輯學家哈斯格爾·科里(haskell curry)將其豐富和發展,currying由此得名。它表示一種將乙個帶有n元組引數的函式轉換成n個一元函式鏈的方法。前面提到的lambda演算使用的都是1元函式,在有兩個或者多個變數的情況下就要使用科里化了。

currying的過程

currying如何進行的呢?不妨來看乙個直觀的例子, 假設有如下函式:f(x, y, z) = x / y +z. 要求f(4,2, 1)的值。

首先,用4替換f(x, y, z)中的x,得到新的函式g(y, z) = f(4, y, z) = 4 / y + z

然後,用2替換g(y, z)中的引數y,得到h(z) = g(2, z) = 4/2 + z

最後,用1替換掉h(z)中的z,得到h(1) = g(2, 1) = f(4, 2, 1) = 4/2 + 1 = 3

很顯然,如果是乙個n元函式求值,這樣的替換會發生n次,注意,這裡的每次替換都是順序發生的,這和我們在做數學時上直接將4,2,1帶入x / y + z求解不一樣。在這個順序執行的替換過程中,每一步代入乙個引數,每一步都有新的一元函式誕生,最後形成乙個巢狀的一元函式鏈。這些一元函式和之前提到的lambda演算中的單輸入的函式是一回事。於是,通過currying,我們可以對任何乙個多元函式進行化簡,使之能夠進行lambda演算。用c#來演繹上述currying的例子就是:

func

<

int,func

<

int, func

<

int, 

int>>>

func =x 

=>

y =>

z=>x/

y +z;console.writeline(func(4)(

2)(1)); 

//顯示3

偏函式應用

這裡以python 3.0中的pfa為例,要用到偏函式功能需要先導入functools模組。

>>>

from

functools 

import

partial

>>>

deff(x,y):

returnx+

y>>>p =

partial(f,1) 

%固定乙個引數1

>>>p(3)4

>>>

p(300

)301

當然,還可以讓乙個函式接收另乙個函式作為引數,比如下面的求和函式:

>>>

defjustsum(func,l):

return

sum([func(item) 

foritem 

inl])

這樣就可以用它來接收我們定義的任意函式,並對它們在l上的值求和了。比方說我們可以通過這樣的方式來求平方和:

>>>

sqrssum 

=partial(justsum,

lambda

x:x*

x)>>>

sqrssum([1,

2,3,

4,5])

55 c#中也有類似地實現,不過受委託強型別的限制,比較難看:-(,(見閱讀資料[3])

閱讀資料

黃季冬2023年10月22日

lambda演算中的遞迴與Y組合子

考慮在 lambda 演算中實現乙個遞迴的階乘函式,f ac t n 1 n 0 n cdot fact n 1 n neq0 end fact n fib n begin 1 n 1 1 n 2 fib n 1 fib n 2 n notin end fib n 1 1fib n 1 fi b n...

006 js實現科里化

柯里化通常也稱部分求值,其含義是給函式分步傳遞引數,每次傳遞引數後部分應用引數,並返回乙個更具體的函式接受剩下的引數,這中間可巢狀多層這樣的接受部分引數函式,直至返回最後結果。因此柯里化的過程是逐步傳參,逐步縮小函式的適用範圍,逐步求解的過程。廢話不多數,直接上 const add a,b,c,d,...

柯里化與反柯里化

柯里化,可以理解為提前接收部分引數,延遲執行,不立即輸出結果,而是返回乙個接受剩餘引數的函式。因為這樣的特性,也被稱為部分計算函式。柯里化,是乙個逐步接收引數的過程。在接下來的剖析中,你會深刻體會到這一點。反柯里化,是乙個泛型化的過程。它使得被反柯里化的函式,可以接收更多引數。目的是建立乙個更普適性...