羅素悖論 型別系統與程式語言
程式語言的基礎核心來自於邏輯,來自PROGRAMMING LANGUAGES & TYPE SYSTEMS文章從羅素悖論角度解釋,為什麼我們引入型別系統,然後才有了今天的程式語言,這對深入理解程式語言來源,破除語言誤區有很大幫助。
著名的羅素悖論是:一個集合到底包含不包含它自己?
舉個例子,如下集合a包含a本身:
a = { a, b }
但是,我們常識中對樹形結構的瞭解,一個節點(枝)是由其他節點組成的(左 右或子),但肯定不是由它自己組成的,因此我們又認為集合a不應該包含a本身:
a={任何除了a的元素}
或a={b}
我們總結下面:
1.集合包含他們自己
2.集合不包含他們自己
如果有很多集合,這些很多集合也可以表現為一個大集合,那麼我們得到如下描述:
1.所有集合的集合應該包含他們自己。
2.所有集合的集合不應該包含他們自己。
從前面推論我們已經知道,我們傾向於第二條為真,但是注意第二句就發生了邏輯矛盾,如果我們需要統計不包含自己的所有集合,必須首先統計其主集合,因為主集合實際上是包含了所有集合的,但是主集合也是一種集合,而集合是不應該包含他們自己的,結果這裡發生矛盾,這就是著名的羅素悖論。
解決羅素悖論是引入型別理論(http://en.wikipedia.org/wiki/Type_theory),引入不同型別的層次,每個層次結構中的層只是由同一型別中先前層次組成的。這就誕生了我們今天現代語言Java, C#, Ruby, Haskell 等等,都是採取型別理論,實現特定的屬性和層次。
知道這種來歷,對於理解程式語言中動態型別(Ruby)和靜態型別(Java Scala)等區別很有幫助,還有一種強型別和弱型別,比如Java如下:
// Given a method:
public void increment(int i);
// This call is illegal
increment(24.0);
增加這個方法是非法的,因為24.0是一種double型別,而方法函式引數型別要求是int,Java並不知道如何將24.0轉換成int型別,但是也不鼓勵由Java自動實現,因為Double在Java中是64位,而int是32位,進行自動轉換會丟失資訊。
但是Java允許 3+24.0這種演算法,這是一種型別擴充套件type-widening表達用法,算式的結果型別是double的,整數int能夠被保護,這種轉換將被允許,但是int x = 3+24.0又不允許。
在動態型別語言Python中"1"+2 結果是錯誤的:
TypeError: cannot concatenate 'str' and 'int' objects
告訴我們範了一個型別錯誤,Python並不知道如何轉換這些型別,同樣Ruby會報類似錯誤,這其實是一種強型別影響的表現,它存在在靜態型別語言Java C#,也存在動態型別語言Ruby Python Scheme中。
為了糾正這種錯誤,我們必須顯式地進行轉換,如Python必須如下:
"1" + str(2) # returns '12'
或者:
int("1") + 2 # returns 3
很顯然Python並不確定"+"(加號)這個運算子應當將字元轉為整數型,它留給程式設計師解決,這是強型別系統中一個最佳實踐。
在java中下面是允許的:
"1" + 2 // returns "12"
這裡"+"加號運算子被認為是呼叫物件的.toString(),這是值得商榷的選擇,但是它增強了靈活性。
在Python中,一個函式能夠接受任何型別的物件:
def fun(arg):
...
這比報型別錯誤要更加安全,相反Java支援強制性型別:
void fun(String arg) { .. }
這是一種更加安全的方式,只接受特定型別引數。
大部分動態型別語言都假設任何物件能夠被轉換成String,這是一種為了方便而實現的妥協。
下面談談弱型別,javascript是一種弱型別語言:
"100" > 10 // returns true
和上面談到的強型別不同的是,弱型別語言定義了一些基本約束,防止程式設計師射中自己的腳,這些型別的自動轉換是語言的特別之處,但是每個語言也有自己在遭遇矛盾型別情況下的解決方式:
100 + "1" + 0
結果將是"10010",而在VB,將是數字101,這種轉換雖然帶來方便,但是也有一定隨意性,這時強型別語言顯示出其特有的可預測的邏輯一致性了。
結論:
強型別Ruby和java對於團隊開發更加安全,而弱型別則可提供快速基於瀏覽器內部的開發 。
著名的羅素悖論是:一個集合到底包含不包含它自己?
舉個例子,如下集合a包含a本身:
a = { a, b }
但是,我們常識中對樹形結構的瞭解,一個節點(枝)是由其他節點組成的(左 右或子),但肯定不是由它自己組成的,因此我們又認為集合a不應該包含a本身:
a={任何除了a的元素}
或a={b}
我們總結下面:
1.集合包含他們自己
2.集合不包含他們自己
如果有很多集合,這些很多集合也可以表現為一個大集合,那麼我們得到如下描述:
1.所有集合的集合應該包含他們自己。
2.所有集合的集合不應該包含他們自己。
從前面推論我們已經知道,我們傾向於第二條為真,但是注意第二句就發生了邏輯矛盾,如果我們需要統計不包含自己的所有集合,必須首先統計其主集合,因為主集合實際上是包含了所有集合的,但是主集合也是一種集合,而集合是不應該包含他們自己的,結果這裡發生矛盾,這就是著名的羅素悖論。
解決羅素悖論是引入型別理論(http://en.wikipedia.org/wiki/Type_theory),引入不同型別的層次,每個層次結構中的層只是由同一型別中先前層次組成的。這就誕生了我們今天現代語言Java, C#, Ruby, Haskell 等等,都是採取型別理論,實現特定的屬性和層次。
知道這種來歷,對於理解程式語言中動態型別(Ruby)和靜態型別(Java Scala)等區別很有幫助,還有一種強型別和弱型別,比如Java如下:
// Given a method:
public void increment(int i);
// This call is illegal
increment(24.0);
增加這個方法是非法的,因為24.0是一種double型別,而方法函式引數型別要求是int,Java並不知道如何將24.0轉換成int型別,但是也不鼓勵由Java自動實現,因為Double在Java中是64位,而int是32位,進行自動轉換會丟失資訊。
但是Java允許 3+24.0這種演算法,這是一種型別擴充套件type-widening表達用法,算式的結果型別是double的,整數int能夠被保護,這種轉換將被允許,但是int x = 3+24.0又不允許。
在動態型別語言Python中"1"+2 結果是錯誤的:
TypeError: cannot concatenate 'str' and 'int' objects
告訴我們範了一個型別錯誤,Python並不知道如何轉換這些型別,同樣Ruby會報類似錯誤,這其實是一種強型別影響的表現,它存在在靜態型別語言Java C#,也存在動態型別語言Ruby Python Scheme中。
為了糾正這種錯誤,我們必須顯式地進行轉換,如Python必須如下:
"1" + str(2) # returns '12'
或者:
int("1") + 2 # returns 3
很顯然Python並不確定"+"(加號)這個運算子應當將字元轉為整數型,它留給程式設計師解決,這是強型別系統中一個最佳實踐。
在java中下面是允許的:
"1" + 2 // returns "12"
這裡"+"加號運算子被認為是呼叫物件的.toString(),這是值得商榷的選擇,但是它增強了靈活性。
在Python中,一個函式能夠接受任何型別的物件:
def fun(arg):
...
這比報型別錯誤要更加安全,相反Java支援強制性型別:
void fun(String arg) { .. }
這是一種更加安全的方式,只接受特定型別引數。
大部分動態型別語言都假設任何物件能夠被轉換成String,這是一種為了方便而實現的妥協。
下面談談弱型別,javascript是一種弱型別語言:
"100" > 10 // returns true
和上面談到的強型別不同的是,弱型別語言定義了一些基本約束,防止程式設計師射中自己的腳,這些型別的自動轉換是語言的特別之處,但是每個語言也有自己在遭遇矛盾型別情況下的解決方式:
100 + "1" + 0
結果將是"10010",而在VB,將是數字101,這種轉換雖然帶來方便,但是也有一定隨意性,這時強型別語言顯示出其特有的可預測的邏輯一致性了。
結論:
強型別Ruby和java對於團隊開發更加安全,而弱型別則可提供快速基於瀏覽器內部的開發 。
相關文章
- 程式語言:型別系統的本質型別
- 概念區別 【編譯型語言與解釋型語言、動態型別語言與靜態型別語言、強型別語言與弱型別語言】編譯型別
- Go 語言型別系統詳解Go型別
- 演算法系列教程02 - 從羅素悖論到圖靈機演算法圖靈
- 淺談強型別語言與弱型別語言,歡迎大家來點評型別
- 語言型別介紹及其Python的語言型別型別Python
- 計算機語言:編譯型/解釋型、動態語言/靜態語言、強型別語言/弱型別語言計算機編譯型別
- Dart語法篇之型別系統與泛型(七)Dart型別泛型
- 程式語言語法:`=`表示賦值,`:`表示型別。賦值型別
- 淺談程式語言型別的強型別,弱型別,動態型別,靜態型別型別
- 解釋型語言、編譯型語言 區別編譯
- 編譯型語言與解釋型語言編譯
- go語言資料型別-基礎型別Go資料型別
- 國產系統級程式語言與編譯器,輕鬆與 C 語言進行互動編譯
- go語言——資料型別Go資料型別
- C語言資料型別C語言資料型別
- C程式設計語言讀書筆記:型別運算子與表示式C程式程式設計筆記型別
- 《Go 語言程式設計》讀書筆記 (七) Goroutine 與系統執行緒的區別Go程式設計筆記執行緒
- 從問題到程式 程式設計與C語言引論pdf程式設計C語言
- Python 語言特性:編譯+解釋、動態型別語言、動態語言Python編譯型別
- Python程式設計基礎(一)程式語言是什麼?編譯型語言和解釋型語言的區別|Python是什麼?Python程式設計編譯
- 企業數字化悖論與對策
- 《Go 語言程式設計》讀書筆記 (一)基礎型別和複合型別Go程式設計筆記型別
- 強型別語言變數和資料型別的理解變數資料型別
- 瞭解 JavaScript 函數語言程式設計-型別簽名JavaScript函數程式設計型別
- 計算機程式語言的分類,解釋型語言、編譯型語言、指令碼語言的關係計算機編譯指令碼
- 【R語言入門】R語言中的變數與基本資料型別R語言變數資料型別
- 1354: 素數判定(C語言)C語言
- 補充:C語言列舉型別C語言型別
- C語言基礎-2、字元型別C語言字元型別
- go語言資料型別轉換Go資料型別
- C語言 列舉資料型別C語言資料型別
- C語言筆記——自定義型別C語言筆記型別
- GO語言————8.4 map 型別的切片Go型別
- [程式設計]UML語言:理論之光與實踐之惑程式設計
- 嵌入式系統軟體及程式語言
- C語言與嵌入式C語言的區別C語言
- 逍遙自在學C語言 | 變數、常量與資料型別C語言變數資料型別
- C語言程式設計入門之--第四章C語言基本資料型別C語言程式設計資料型別