你的程式語言可推導(Reasonable)嗎?
在函式程式設計世界中,我們經常說“reason about可推導”,或者說,我們要讓我們的程式可推導。那麼這個可推導是什麼意思呢?
上面是一段Javascript程式碼,你能判斷最後y值是多少嗎?答案是-1,為什麼?下面是整個事情真相:
是的,如此可怕,Dosomething直接訪問x而不是透過引數,這樣它將其轉為一個boolean,那麼從x減1就會將x實現cast,從false變為0;那麼y結果是-1。
你是否很討厭這樣,很抱歉誤導了你,這裡只是想說明當語言不可預期的時候變得多麼討厭。
Javascript是非常有用重要的語言,但是沒有人宣稱可推導是它的強項,實際上,大多數動態語言都是這樣難以可推導。
而C#要比Javascript更加更具有預期性,這是靜態語言加分之處。但是還是有問題,待續。
現在我們有了讓語言變得可預期的第一個法則:
1.變數不應該允許改變它們的型別。
案例2. 我們要建立Customer類的兩個例項,那麼它們相等嗎?
答案是不可知,因為這個依賴於Customer是如何實現的,也就是Customer內部程式碼,因此這段程式碼不可預期。至少你得看到這個類是否實現IEquatable。
案例3:
這也無法知道,因為這是兩個不同類的物件。(banq注:這種質疑有點苛刻,哪個程式設計師腦子有病去比較不同型別呢?而對於動態語言,苛刻的型別質疑會失去靈活性。原來喜歡質疑的人有時會鑽牛角尖的原因所在,不夠靈活)
案例4:
這也無法預期知道輸出什麼,因為不知道Address 這個屬性是否為空或不是,也就是說,當一個物件被初始化時,應該在構造器中將其內部初始化到一個有效狀態。當然如果語言幫助我們做到就更棒。
案例5:
1.建立一個customer.
2.加入到一個集合set,該集合使用hashing.
3.對customer做些事情
4.看看customer是否還在集合中?
那麼集合中是否還包含Cumster這個物件呢?也許,也許不是。因為處理cust物件時有可能將其從集合中移除,如果我們假定無論物件和集合一旦建立就無法改變,不可變的,那麼我們就能得出肯定的結論。
案例6:
我們從倉儲CustomerRepository獲取一個customer:
問題是:我們做完customer = repo.GetById(42)以後,customer.Id的值是多少?這也是無法推導的。
如果repo.GetById方法返回空或丟擲Exception,你能從customer中獲得Id嗎?
如果假設你的語言不允許null,並且不允許丟擲Exception,那麼你能得出什麼結論?那麼你會得到CustomerOrError類,其包含一個customer或一個錯誤。
在函式程式語言F中,以上案例的約束都是內建的:
1.值不允許被改變型別(甚至包括暗地裡對int cast到float).
2.內部包含同樣資料的記錄預設是相等的。
3.比較不同型別的值會發生編譯錯誤。
4.值必須被初始化到一個有效狀態,不這樣做會編譯出錯。
5.一旦建立,值預設不可變。
6.空Null是不允許的。
Is your programming language unreasonable? | F# fo一文以比較通俗方式解釋了reason。
很多人說C已經具有了F的大多數函式功能,是否沒有必要轉到F#?同樣問題也存在Java和Scala之間。其實這些新舊語言的本質區別就是是否可推導。
reasoning意思來自於數學和邏輯,但是可以使用簡單實用的方式定義如下:
"reasoning about the code(程式碼是否可推導 是否合理 是否經得起推敲質疑)" 的意思是:你是否可以根據當前眼前的資訊就能得出結論,下判斷?而不是需要進入程式碼內部研究一番才敢判斷。
(banq注:在日常生活中,喜歡下結論的方式其實是草率的思維方式,因為日常我們所見到所聽到資訊都不是可推導的,如果你在純數學理論世界習慣了,會造成濫用“下結論”哦)。
從另外一個方面說,你只要看到一部分程式碼的行為,你就能有預期,你只需要理解介面,而不必理解介面背後具體實現做什麼,你就能預期判斷了。
有很多方式指導如何達到這種目標:如取名指南,格式規則,設計模式等等。
下面以一段程式碼說明如何使得程式碼變得更加可推導,可預期:
var x = 2; DoSomething(x); // What value is y? var y = x - 1; <p class="indent"> |
上面是一段Javascript程式碼,你能判斷最後y值是多少嗎?答案是-1,為什麼?下面是整個事情真相:
function DoSomething (foo) { x = false} var x = 2; DoSomething(x); var y = x - 1; <p class="indent"> |
是的,如此可怕,Dosomething直接訪問x而不是透過引數,這樣它將其轉為一個boolean,那麼從x減1就會將x實現cast,從false變為0;那麼y結果是-1。
你是否很討厭這樣,很抱歉誤導了你,這裡只是想說明當語言不可預期的時候變得多麼討厭。
Javascript是非常有用重要的語言,但是沒有人宣稱可推導是它的強項,實際上,大多數動態語言都是這樣難以可推導。
而C#要比Javascript更加更具有預期性,這是靜態語言加分之處。但是還是有問題,待續。
現在我們有了讓語言變得可預期的第一個法則:
1.變數不應該允許改變它們的型別。
案例2. 我們要建立Customer類的兩個例項,那麼它們相等嗎?
// create two customers var cust1 = new Customer(99, "J Smith"); var cust2 = new Customer(99, "J Smith"); // true or false? cust1 == cust2; <p class="indent"> |
答案是不可知,因為這個依賴於Customer是如何實現的,也就是Customer內部程式碼,因此這段程式碼不可預期。至少你得看到這個類是否實現IEquatable。
案例3:
// create a customer and an order var cust = new Customer(99, "J Smith"); var order = new Order(99, "J Smith"); // true or false? cust.Equals(order); <p class="indent"> |
這也無法知道,因為這是兩個不同類的物件。(banq注:這種質疑有點苛刻,哪個程式設計師腦子有病去比較不同型別呢?而對於動態語言,苛刻的型別質疑會失去靈活性。原來喜歡質疑的人有時會鑽牛角尖的原因所在,不夠靈活)
案例4:
// create a customer var cust = new Customer(); // what is the expected output? Console.WriteLine(cust.Address.Country); <p class="indent"> |
這也無法預期知道輸出什麼,因為不知道Address 這個屬性是否為空或不是,也就是說,當一個物件被初始化時,應該在構造器中將其內部初始化到一個有效狀態。當然如果語言幫助我們做到就更棒。
案例5:
1.建立一個customer.
2.加入到一個集合set,該集合使用hashing.
3.對customer做些事情
4.看看customer是否還在集合中?
// create a customer var cust = new Customer(99, "J Smith"); // add it to a set var processedCustomers = new HashSet<Customer>(); processedCustomers.Add(cust); // process it ProcessCustomer(cust); // Does the set contain the customer? true or false? processedCustomers.Contains(cust); <p class="indent"> |
那麼集合中是否還包含Cumster這個物件呢?也許,也許不是。因為處理cust物件時有可能將其從集合中移除,如果我們假定無論物件和集合一旦建立就無法改變,不可變的,那麼我們就能得出肯定的結論。
案例6:
我們從倉儲CustomerRepository獲取一個customer:
// create a repository var repo = new CustomerRepository(); // find a customer by id var customer = repo.GetById(42); // what is the expected output? Console.WriteLine(customer.Id); <p class="indent"> |
問題是:我們做完customer = repo.GetById(42)以後,customer.Id的值是多少?這也是無法推導的。
如果repo.GetById方法返回空或丟擲Exception,你能從customer中獲得Id嗎?
如果假設你的語言不允許null,並且不允許丟擲Exception,那麼你能得出什麼結論?那麼你會得到CustomerOrError類,其包含一個customer或一個錯誤。
在函式程式語言F中,以上案例的約束都是內建的:
1.值不允許被改變型別(甚至包括暗地裡對int cast到float).
2.內部包含同樣資料的記錄預設是相等的。
3.比較不同型別的值會發生編譯錯誤。
4.值必須被初始化到一個有效狀態,不這樣做會編譯出錯。
5.一旦建立,值預設不可變。
6.空Null是不允許的。
相關文章
- 你的程式語言能這樣做嗎?
- Go 是物件導向的語言嗎?Go物件
- 你真的理解函數語言程式設計嗎?函數程式設計
- 你真的理解【函數語言程式設計】嗎?函數程式設計
- 你真的需要了解多種程式語言嗎?
- 程式語言的可讀性
- GO是更好的程式語言嗎?Go
- 【譯】你的程式語言能做到這個嗎?(為什麼要學函數語言程式設計)函數程式設計
- 【面試官問】你懂函數語言程式設計嗎?面試函數程式設計
- C語言的角落——這些C語言不常用的特性你知道嗎?C語言
- 敢為你最寵愛的程式語言賭100000000美元嗎?
- 你需要掌握的三種程式語言
- 最值得你學習的程式語言
- 前端的你常用的程式語言有哪些?前端
- 論機器學習和程式語言:ML需要專用的計算機語言嗎?機器學習計算機
- java是最值得學習的程式語言嗎?Java
- 2018年最流行的十大程式語言,有你用的嗎?
- 大資料:程式語言真的重要嗎?大資料
- “春節十二響”C語言程式碼開源了,你要提 PR 嗎?C語言
- Ohm:用 JavaScript 創造你的程式語言JavaScript
- 學習你的第一門程式語言
- 世界上最好的語言PHP 爆出高危漏洞:你信嗎?PHP
- Facebook 開源 Skip 物件導向+函數語言程式設計語言物件函數程式設計
- 你想要了解GO語言嗎?帶你入門!Go
- JavaScript 函數語言程式設計導論JavaScript函數程式設計
- 存在可能替代C語言的其他語言嗎? -Erik EngheimC語言
- 如何挑選你的第一門程式語言
- 你最深愛的程式語言其實很爛
- 如何選擇你的第一門程式語言
- 你最喜愛的程式語言不夠好
- 幫你提升 Python 的 27 種程式語言Python
- 最‘乾淨’的程式語言——空白程式語言
- Go 語言實戰: 編寫可維護 Go 語言程式碼建議Go
- 中文程式語言——易語言,到底是用來幹什麼的?易語言值得學習嗎?易語言的優勢有什麼?
- 學習遊戲要學習程式語言嗎?十大主流程式語言解析遊戲
- Go語言 | 你還在這樣獲取檔案的大小嗎?Go
- 有哪一種程式語言比其他的更安全嗎?
- 英語不好,能學好程式設計嗎?其實這幾門語言很適合想學的你程式設計