Haskell/型別雜談
到目前為止,我們只接觸過整數和列表,雖然也略微提到了字串和字元。本節將涵蓋主要的型別。
理解 Haskell 的內建型別的一個重要方面是,它們並不特殊。從編譯器的角度來看,它們很特殊,因為處理器有專門的操作來進行整數加法等操作。但從程式設計師的角度來看,它們只是普通的型別,擁有普通的函式,遵循與其他型別相同的規則。因此,本節內容很少解釋如何使用這些型別或規則是什麼,因為大多數情況下您已經瞭解了它們:如果它適用於整數,那麼它也適用於字串、布林值和浮點數。
Haskell 有兩種整數型別:Int 和 Integer。
"Integer" 是任意精度的型別:它可以儲存任意大的數字,直到機器記憶體的限制。這就是為什麼 "factorial 1000" 會給出正確答案的原因。這意味著您永遠不會遇到算術溢位。另一方面,這也意味著您的算術運算相對緩慢。Lisp 使用者可能認出這裡的 "bignum" 型別。
"Int" 是更常見的 32 或 64 位整數。實現方式可能有所不同,但保證至少為 30 位。
Haskell 也有兩種浮點型別:Float 和 Double。它們的行為類似於 C 中的對應型別。
所有常見的運算子都存在,還有一些額外的運算子。
- 旁註:Haskell 的數字型別在型別類的複雜層次結構中相互關聯,這些型別類將在後面介紹。本頁的目的是讓您能夠進行普通的算術運算,而不會被型別系統絆倒。
有三個 "冪運算" 運算子,它們的工作方式不同,接受的型別也不同。
- **
- 接受兩個浮點數,使用對數來計算冪。
- ^^
- 接受一個分數(例如浮點數或比例,後面會講到)並將其提升到正或負整數冪。
- ^
- 接受任何數字型別並將其提升到正整數冪。
從整數型別(Int 或 Integer)轉換為其他任何型別是透過 "fromIntegral" 完成的。目標型別是自動推斷的。例如
n :: Integer n = 6 x :: Float x = fromIntegral n m :: Int m = 7 y :: Double y = fromIntegral m
將定義 x 為 6.0,y 為 7.0。
整數除法有點複雜。如果您對整數使用普通的 "/" 運算子,那麼您會收到錯誤訊息(雖然表示式 "4/3" 可以工作,因為 Haskell 會在必要時將文字整數提升為浮點數)。相反,整數除法是使用一組命名的運算子完成的。
Haskell 在運算子方面有一個巧妙的技巧:您可以將任何接受兩個引數的函式用反引號括起來,使其像運算子一樣使用。因此,以下兩行表示完全相同的意思
d = 7 `div` 3 d = div 7 3
考慮到這一點,以下是整數除法運算子
- quot
- 返回兩個數字的商。這是除法運算的結果,然後被截斷為零。
- rem
- 返回商的餘數。
- div
- 類似於 "quot",但向下舍入到負無窮。
- mod
- 返回兩個數字的模。這類似於餘數,但在 "div" 返回負數時有不同的規則。
只要 y 不是負數,以下兩個方程始終成立
(x `quot` y)*y + (x `rem` y) == x (x `div` y)*y + (x `mod` y) == x
就像您可以將接受兩個引數的函式轉換為運算子一樣,您也可以將運算子轉換為接受兩個引數的函式:只需將其放在括號中。因此,以下兩行表示相同的意思
(+) 3 4 3 + 4
這也可以對任何 "不完整的" 運算子應用進行
(3+) 4 (+4) 3 -- not 3 (+4)
Haskell 具有布林型別Bool,有兩個值True和False。該型別上還定義了兩個運算子Bool型別&&和||.
數字、字元和字串可以使用通常的比較運算子進行比較,以生成一個 Bool 值
- ==
- 相等。
- /=
- 不相等。
- <=
- 小於或等於。
- >=
- 大於或等於。
- <
- 小於。
- >
- 大於。
(當您瞭解到 型別類 時,請注意,相等運算子 (==, /=) 是型別類的一部分Eq,比較運算子 (<=, >=, <, >) 是型別類的一部分Ord.)
Haskell 有一個 "if-then-else" 子句,但由於 Haskell 是一種函式式語言,它更類似於 C 中的 "? :" 運算子:它不是 "執行" "then" 子句或 "else" 子句,而是整個表示式計算出其中一個子句的值。例如,階乘函式可以寫成
factorial n =
if n <= 0
then 1
else n * factorial (n-1)
一個if表示式的語法是
if <condition> then <true-value> else <false-value>
如果條件為 True,那麼 "if" 的結果就是真值,否則就是假值。