[Haskell筆記]符號
在上一節中你已經做了不少算術題吧?再來一道何如?
求半徑為5cm的圓的面積。
圓面積公式為s = πr2,所以我們在GHCi中輸入:
Prelude> 3.14 * 5^2 78.5
答案是78.5平方厘米。這裏,我們取pi=3.14。我們可以把pi的近似值可以取得更精確些,反正是電腦替我們算。
Prelude> 3.14159265358979323846264338327950 * (5 ^ 2) 78.53981633974483
計算了面積,不妨再算一下這個圓的周長:
Prelude> 2 * 3.14159265358979323846264338327950 * 5 31.41592653589793
如果,圓的半徑是25,那面積又是多少呢?
Prelude> 3.14159265358979323846264338327950 * (25 ^ 2) 1963.4954084936207
你該對重復輸入pi的近似值感到厭煩了吧?(或者是對不斷地復制、粘貼感到厭煩。甚至,你可能已經利用上箭頭來回顧上一個命令。是的,你可以使用上箭頭,就像在Bash中一樣!)事實上,編程的意義就在於避免重復乏味的工作。在自然語言中,當一個詞過長時,我們往往會給它起個縮略名,比如,我們一直在提GHC,而不是Glasgow Haskell Compiler。有一些輸入法,比如fcitx,支持自定義詞組,以節省擊鍵。在Haskell中,我們也可以這麽做。
Prelude> let pi = 3.14159265358979323846264338327950
這裏,我們用pi來代表3.14159265358979323846264338327950。換句話說,我們引入了一個符號(symbol)pi,它的值為3.14159265358979323846264338327950。以後,當我們需要用到3.14159265358979323846264338327950的時候,就可以輸入pi。
Prelude> pi 3.141592653589793
怎麽少了幾位?別擔心,這只是為了顯示上的整潔。後面的幾位并沒有被吞掉,在以後的計算中,仍然是根據我們先前定義的值(而不是顯示出的值)。
這樣,上面的三道題就可以這樣輸入了:
Prelude> pi * (5 ^ 2) 78.53981633974483 Prelude> 2 * pi * 5 31.41592653589793 Prelude> pi * (25 ^ 2) 1963.4954084936207
接下來,也許你想用r來代表半徑5。
Prelude> let r = 25 Prelude> 2 * pi * r
咦?出錯了?
<interactive>:1:9:
Couldn't match `Double' against `Integer'
Expected type: Double
Inferred type: Integer
In the second argument of `(*)', namely `r'
In the definition of `it': it = 2 * pi * r
怎麽回事?這裏涉及到Haskell中的一個重要概念:類型(type)。在上面這個例子中,r(25)的類型是Integer(整數),而pi的類型則是Double(浮點數)。r和pi類型不同,不能相乘。
這裏有兩個問題。首先,為什麽要有類型?如果沒有類型,或者,把類型分得粗一些,不就少了很多麻煩嗎?這個問題就說來話長了。簡單的說,類型有助於我們及時地發現編程中的錯誤。
其次,我們并沒有說pi是Double,r是Integer啊!Haskell是怎麽知道的呢?答案是:猜的!這也正是出現錯誤的原因,Haskell猜錯了我們的意圖。25可以被認為是Integer,也可以被認為是Double,在沒有其它信息的情況下,Haskell猜它是Integer。
所以,要避免這個錯誤,我們直接告訴Haskell,r是Double。那就不會出錯了。
Prelude> let r = 25 :: Double Prelude> 2 * pi * r 157.07963267948966
那我們是否有必要告訴Haskell pi是Double呢?可以,但是沒有必要。因為上下文提供了足夠的信息,Haskell足以判斷了。事實上,大多數情況下,Haskell都能都根據語境成功推斷出類型,不用我們每次都指明類型。
也許,我們可以讓Haskell更“聰明”一些,這樣,它就能正確判斷出r應該被看作Double,而不是Integer。事實上,Haskell可以更“聰明”(GHC有-fno-monomorphism-restriction這樣一個flag(標記)),但是Haskell默認保持比較“笨”的狀態。因為更“聰明”的代價是要做更多的計算,這大大影響了程序的效率。
順便提一下,首字母大寫的字符串(包括單個大寫字母)不能用來作符號,因為它們另有它用。具體用途,以後再說。(如果你夠聰明,看到上面寫的是Double和Integer,而不是double和integer,應該已經猜到答案了。)
Leave a Reply