国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

函數式編程與面向對象編程[1]: Lambda表達式 函數柯里化 高階函數

張金寶 / 948人閱讀

摘要:函數式編程與面向對象編程表達式函數柯里化高階函數之劍什么是表達式例子定義表達式是一個匿名函數,表達式基于數學中的演算得名,直接對應于其中的抽象,是一個匿名函數,即沒有函數名的函數。

函數式編程與面向對象編程[1]: Lambda表達式 函數柯里化 高階函數.md

之劍

2016.5.2 11:19:09

什么是lambda表達式 例子

For example, in Lisp the "square" function can be expressed as a lambda expression as follows:

(lambda (x) (* x x))
定義

“Lambda 表達式”(lambda expression)是一個匿名函數,Lambda表達式基于數學中的λ演算得名,直接對應于其中的lambda抽象(lambda abstraction),是一個匿名函數,即沒有函數名的函數。Lambda表達式可以表示閉包(注意和數學傳統意義上的不同)。

Lambda calculus (also written as λ-calculus) is a formal system in mathematical logic for expressing computation based on function abstraction and application using variable binding and substitution. It was first introduced by mathematician Alonzo Church in the 1930s as part of an investigation into the foundations of mathematics. Lambda calculus is a universal model of computation equivalent to a Turing machine (Church-Turing thesis, 1937). Its namesake, Greek letter lambda (λ), is used in lambda terms (also called lambda expressions) to denote binding a variable in a function.

Lambda calculus may be typed and untyped. In typed lambda calculus functions can be applied only if they are capable of accepting the given input"s "type" of data.

Lambda calculus has applications in many different areas in mathematics, philosophy,linguistics, and computer science. Lambda calculus has played an important role in the development of the theory of programming languages. Functional programming languages implement the lambda calculus. Lambda calculus also is a current research topic in Category theory.

λ演算(λ-calculus)

Lambda演算和函數式語言的計算模型天生較為接近,Lambda表達式一般是這些語言必備的基本特性。如:

Scheme:

    
(lambda(x)(+x1))

Haskell:

    
x->x+1

λ演算是一套用于研究函數定義、函數應用和遞歸的形式系統。函數的作用 (application) 是左結合的:

f x y = (f x) y

它包括一條變換規則 (變量替換) 和一條函數定義方式.

比如說,下面的這個圓錐曲線二元二次函數:

$$f(x,y)=x^2+y^2$$

讓我們用其他的一些方式來表達:

匿名函數表達

$$(x,y) rightarrow x^2 + y^2$$

柯里化表達

$$x rightarrow (y rightarrow x^2 + y^2 )$$

演算過程

為了更加簡單的理解其演算過程, 分解各個步驟如下:

數學函數表達式: (f(5,2) = 5^2 + 2^2 = 29)

匿名函數式:( ((x,y) rightarrow (x^2 + y^2)) (5,2) = 5^2 + 2^2 = 29)

柯里化函數式: ( (x rightarrow ( y rightarrow (x^2 + y^2) )(5))(2)=(y rightarrow (5^2+y^2))(2) = 5^2+2^2=29 )

lambda演算的歷史

λ演算由 Alonzo Church 和 Stephen Cole Kleene 在 20 世紀三十年代引入,Church 運用 lambda 演算在 1936 年給出 判定性問題 (Entscheidungsproblem) 的一個否定的答案。這種演算可以用來清晰地定義什么是一個可計算函數。關于兩個 lambda 演算表達式是否等價的命題無法通過一個通用的算法來解決,這是不可判定性能夠證明的頭一個問題,甚至還在停機問題之先。Lambda 演算對函數式編程有巨大的影響,特別是Lisp 語言。

Church 整數

在 lambda 演算中有許多方式都可以定義自然數,但最常見的還是Church 整數,下面是它們的定義:

$$ 0 = lambda fcdot lambda xcdot x $$
$$ 1 = lambda fcdot lambda xcdot f x $$
$$ 2 = lambda fcdot lambda xcdot f (f x ) $$
$$ 3 = lambda fcdot lambda xcdot f(f (f x )) $$
$$...$$
$$ n = lambda fcdot lambda xcdot f^n( x ) $$

以此類推。直觀地說,lambda 演算中的數字 n 就是一個把函數 f 作為參數并以 f 的 n 次冪為返回值的函數。換句話說,Church 整數是一個高階函數 :

 以單一參數函數 f 為參數,返回另一個單一參數的函數。

(注意在 Church 原來的 lambda 演算中,lambda 表達式的形式參數在函數體中至少出現一次,這使得我們無法像上面那樣定義 0)

C#Lambda表達式

C#的Lambda 表達式都使用 Lambda 運算符 =>,該運算符讀為“goes to”。語法如下:

形參列表=>函數體
(input parameters) => expression
(input parameters) => {statement;}

函數體多于一條語句的可用大括號括起。例子:

() => Console.Write("0個參數")
I => Console.Write("1個參數時參數列中可省略括號,值為:{0}",i)
(x,y) => Console.Write("包含2個參數,值為:{0}*{1}",x,y)

//兩條語句時必須要大括號
I => { i++;Console.Write("兩條語句的情況"); }

Lambda 表達式是一種可用于創建委托或表達式目錄樹類型的匿名函數。 通過使用 lambda 表達式,可以寫入可作為參數傳遞或作為函數調用值返回的本地函數。 Lambda 表達式對于編寫 LINQ 查詢表達式特別有用。

若要創建 Lambda 表達式,需要在 Lambda 運算符 => 左側指定輸入參數(如果有),然后在另一側輸入表達式或語句塊。 例如,lambda 表達式 x => x * x 指定名為 x 的參數并返回 x 的平方值。

過濾條件:

List users = new List();
Func predicate = ((user) =>
    {
        return user.UserId > 100;
    }
);
List temps = users.Where(predicate).ToList();
Java Lambda表達式

Java 8的一個大亮點是引入Lambda表達式,使用它設計的代碼會更加簡潔。當開發者在編寫Lambda表達式時,也會隨之被編譯成一個函數式接口。下面這個例子就是使用Lambda語法來代替匿名的內部類,代碼不僅簡潔,而且還可讀。
沒有使用Lambda的老方法:

Runnable r = new Runnable(){
@Override
public void run(){
    System.out.println("Running without Lambda");
}
};

使用Lambda表達式:

Runnable r =() -> {
    System.out.println("Running without Lambda");
};

C++ Lambda表達式

ISO C++ 11 標準的一大亮點是引入Lambda表達式。基本語法如下:

[capture list] (parameter list) ->return type { function body }

其中除了“[ ]”(其中捕獲列表可以為空)和“復合語句”(相當于具名函數定義的函數體),其它都是可選的。它的類型是唯一的具有成員operator()的非聯合的類類型,稱為閉包類型(closure type)。
C++中,一個lambda表達式表示一個可調用的代碼單元。我們可以將其理解為一個未命名的內聯函數。它與普通函數不同的是,lambda必須使用尾置返回來指定返回類型。

scala的匿名函數

scala的匿名函數使用非常的廣泛,這也是函數式語言的標志之一。

scala中的集合類List有一個map方法,該方法接收一個函數作為參數,對List中的每一個元素使用參數指定的方法,此處非常適合用匿名函數,請看下面代碼:

val l=List(1,2,3)
l.map(i=>i+9)

上面代碼的第二行map函數的參數就是一個匿名函數,或者是lambda表達式。

i=>i+9中的=>是參數列表和返回值的分隔符,如果少于兩個參數可以不寫小括號,后面部分是函數的返回值。如果函數體包含多行代碼可以使用花括號,例如:

l.map((i)=>{
  println("HI");
  i+9
})
scala函數特有特性之調配curried

定義常規的scala add函數:

def add (i:Int,j:Int):Int=i+j

這個函數太簡單了.

我們定義一個devide函數實現除法,一般我們會這么寫:

// 多參數的寫法
def multiply(x: Int, y: Int) = x * y

Moses Schnfinkel 和 Gottlob Frege 發明了如下的表達方式:

def multiply(x: Int)(y: Int) => x * y

這個函數和上面的函數不同之處在于它的參數列表,是一個參數一個小括號,不是把所有參數都放到一個括號內的。下面我們通過實際的例子來理解scala的curried。

我們要定義一個乘法函數:

// 柯里化的寫法
def multiply(x: Int)(y: Int) = x * y

// 計算兩個數的乘積
multiply(6)(7)
 

multiply(6)返回的是函數(y: Int)=>6*y,再將這個函數應用到7

(6 * y ) (7) = 42

最終得到結果42.

這就是scala的乘法函數了.

curried不太好理解,enjoy it!函數柯里化的主要功能是提供了強大的動態函數創建方法,通過調用另一個函數并為它傳入要柯里化(currying)的函數和必要的參數而得到。通俗點說就是利用已有的函數,再創建一個動態的函數,該動態函數內部還是通過已有的函數來發生作用.

我們在想, 這些計算機科學家,數學家們腦子里天天都在想些什么? 盡發明一些普通人不好理解的概念. 但是, 存在即合理.既然這玩意存在著,必定表明必有其存在之意義.

多參數是個虛飾,不是編程語言的根本性的特質。利用柯里化把某個函數參數多帶帶拎出來,提供更多用于類型推斷的信息.

在計算機科學中,柯里化(Currying)是把接受多個參數的函數變換成接受一個單一參數(最初函數的第一個參數)的函數,并且返回接受余下的參數且返回結果的新函數的技術。這個技術由 Christopher Strachey 以邏輯學家 Haskell Curry 命名的,盡管它是 Moses Schnfinkel 和 Gottlob Frege 發明的。

在直覺上,柯里化聲稱“如果你固定某些參數,你將得到接受余下參數的一個函數”。所以對于有兩個變量的函數yx,如果固定了 y = 2,則得到有一個變量的函數 2x。
在理論計算機科學中,柯里化提供了在簡單的理論模型中比如只接受一個單一參數的lambda 演算中研究帶有多個參數的函數的方式。

柯里化特性決定了它這應用場景。提前把易變因素,傳參固定下來,生成一個更明確的應用函數。最典型的代表應用,是bind函數用以固定this這個易變對象。

Function.prototype.bind = function(context) {
    var _this = this,
    _args = Array.prototype.slice.call(arguments, 1);
    return function() {
        return _this.apply(context, _args.concat(Array.prototype.slice.call(arguments)))
    }
}

柯里化其實本身是固定一個可以預期的參數,并返回一個特定的函數。這增加了函數的適用性,但同時也降低了函數的適用范圍。這個思路有點像微積分里面的多重積分的處理方式.

柯里化的本質就是函數參數單一化. 因為多參數有其問題.你在寫很多高階函數的時候,你都得考慮你的 參數函數f 在面臨各種傳參方式的情況下要怎么處理,這事兒是痛苦并且容易忘記的,因為你本不應該關心f的參數是些啥的!盲目地引入傳遞多參的機制,其實是沒有把問題想明白的表現。語法層面支持的多參函數定義是一種扁平、簡單、有效的方式,但是,當程序需要做高階函數抽象的時候,這種方式會帶來麻煩。

通過組合型數據來傳遞復雜參數,是一種很自然的方式,這種情況下并不需要刻意考慮“多參函數”這種問題,并且這種方式對于做高階函數抽象非常友好。

科里化的方式定義多參函數,同樣是一種自然產生的方式,只要把函數當做一等公民,就會存在科里化的方式。科里化的方式使得我們的函數可以更細粒度地方便地組合。

但是,是否要使用科里化的方式,卻是一件需要細細揣摩的事情。比如,我要定義一個rotate函數,它接受一個二維向量的坐標,返回一個逆時針旋轉九十度后的向量坐標,那么你可能會把它定義成

rotate = (x -> (y -> (y, -x)))

或者

rotate = ((x, y) -> (y, -x))

你覺得哪種定義方式比較好呢? 在這個例子里,顯然是第二種定義方式比較好,

一來,二維向量的兩個坐標通常是成對出現的,很少會有“部分應用”的需要,所以也就自然用不到科里化的任何好處;

二來,當你需要把一個向量rotate兩次的時候,科里化版本就會體現出異常的麻煩了。

所以,結論是:

    
    如果某些參數在大部分情況下,總是需要同時給出,才具有真實的意義,那么應該把這些參數組合成一個組合型參數來處理,而不應該科里化。
    如果要定義的多參函數是一個閉合函數,那么它是很可能需要被多次應用的,這種情況下,應該用組合型參數的方式來處理。
    如果先指定某一些參數就有明確的意義,那么就應該用科里化的方式來處理。

在F#里,各種函數的signature 都是 int -> int -> int ->什么的……
what does that even mean??
Currying和partial application對于functional programming有怎樣的真正的威力?

currying和partial application會affect performance嗎?

匿名函數

函數不一定需要名稱:

(x: Double) => 3 * x  // 該匿名函數將傳給它的參數乘3

可以將匿名函數賦值給變量,也可以當參數傳遞。

高階函數(Higher-order function) 變量可以指向函數

以Python內置的求絕對值的函數abs()為例,調用該函數用以下代碼:

abs(-10)
10

但是,如果只寫abs呢?

abs

可見,abs(-10)是函數調用,而abs是函數本身。

要獲得函數調用結果,我們可以把結果賦值給變量:

 x = abs(-10)
 x
10

但是,如果把函數本身賦值給變量呢?

f = abs
f

結論:函數本身也可以賦值給變量,即:變量可以指向函數。

如果一個變量指向了一個函數,那么,可否通過該變量來調用這個函數?用代碼驗證一下:

f = abs
f(-10)
10

成功!說明變量f現在已經指向了abs函數本身。

函數名也是變量

那么函數名是什么呢?函數名其實就是指向函數的變量!對于abs()這個函數,完全可以把函數名abs看成變量,它指向一個可以計算絕對值的函數!

高階函數

既然變量可以指向函數,函數的參數能接收變量,那么一個函數就可以接收另一個函數作為參數,這種函數就稱之為高階函數。

一個最簡單的高階函數:

def add(x, y, f):
    return f(x) + f(y)
    
    

當我們調用add(-5, 6, abs)時,參數x,y和f分別接收-5,6和abs,根據函數定義,我們可以推導計算過程為:

x ==> -5
y ==> 6
f ==> abs
f(x) + f(y) ==> abs(-5) + abs(6) ==> 11

用代碼驗證一下:

add(-5, 6, abs)
11

編寫高階函數,就是讓函數的參數能夠接收別的函數。

把函數作為參數傳入,這樣的函數稱為高階函數,函數式編程就是指這種高度抽象的編程范式。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/65863.html

相關文章

  • JavaScript函數編程1):基本思想

    摘要:中的函數式編程思想匿名函數在函數式編程語言中,函數是可以沒有名字的,匿名函數通常表示可以完成某件事的一塊代碼。匿名函數中包含對的局部變量的引用,因此當返回時,的值被保留不會被垃圾回收機制回收,持續調用,將會改變的值。 1 函數式編程簡介 函數式編程是和傳統命令式編程區分的一種編程思想,在函數式編程語言中,函數是第一類的對象,也就是說,函數 不依賴于任何其他的對象而可以獨立存在,而在面向...

    時飛 評論0 收藏0
  • JavaScript函數編程1):基本思想

    摘要:中的函數式編程思想匿名函數在函數式編程語言中,函數是可以沒有名字的,匿名函數通常表示可以完成某件事的一塊代碼。匿名函數中包含對的局部變量的引用,因此當返回時,的值被保留不會被垃圾回收機制回收,持續調用,將會改變的值。 1 函數式編程簡介 函數式編程是和傳統命令式編程區分的一種編程思想,在函數式編程語言中,函數是第一類的對象,也就是說,函數 不依賴于任何其他的對象而可以獨立存在,而在面向...

    y1chuan 評論0 收藏0
  • 函數編程

    摘要:函數式編程是聲明式而不是命令式,并且應用程序狀態通過純函數流轉。與面向對象編程不同,函數式編程避免共享狀態,它依賴于不可變數據結構和純粹的計算過程來從已存在的數據中派生出新的數據。而函數式編程傾向于復用一組通用的函數功能來處理數據。 面向對象編程和面向過程編程都是編程范式,函數式編程也是一種編程范式,意味著它們都是軟件構建的思維方式。與命令式或面向對象代碼相比,函數式代碼傾向于更簡潔、...

    王晗 評論0 收藏0
  • 編程函數編程

    摘要:聲明式編程一種編程范式,與命令式編程相對立。常見的聲明式編程語言有數據庫查詢語言,正則表達式邏輯編程函數式編程組態管理系統等。函數式編程,特別是純函數式編程,嘗試最小化狀態帶來的副作用,因此被認為是聲明式的。 編程范式與函數式編程 一、編程范式的分類 常見的編程范式有:函數式編程、程序編程、面向對象編程、指令式編程等。在面向對象編程的世界,程序是一系列相互作用(方法)的對象(Class...

    noONE 評論0 收藏0
  • ES6函數Lambda演算

    摘要:高階函數函數式編程中,接受函數作為參數,或者返回一個函數作為結果的函數通常就被稱為高階函數。均屬于高階函數,高階函數并不神秘,我們日常編程也會用到。參考演算函數式編程指南入門康托爾哥德爾圖靈永恒的金色對角線原文函數與演算 緣起 造了一個輪子,根據GitHub項目地址,生成項目目錄樹,直觀的展現項目結構,以便于介紹項目。歡迎Star。 repository-tree 技術棧: ES6 ...

    fasss 評論0 收藏0

發表評論

0條評論

張金寶

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<