Haskell - 型別和型別類



Haskell 是一種函式式語言,並且是強型別語言,這意味著整個應用程式中使用的的資料型別在編譯時都會被編譯器知曉。

內建型別類

在 Haskell 中,每個語句都被視為一個數學表示式,並且此表示式的類別稱為型別。你可以將“型別”視為編譯時使用的表示式的型別。

要了解更多關於型別的資訊,我們將使用“:t”命令。一般來說,型別可以被視為一個值,而型別類可以被視為一組類似型別的集合。在本章中,我們將學習不同的內建型別。

Int

Int 是一個表示整數型別資料的型別類。從 -2147483647 到 2147483647 之間的每個整數都屬於Int 型別類。在下面的示例中,函式fType()將根據其定義的型別進行操作。

fType :: Int -> Int -> Int 
fType x y = x*x + y*y
main = print (fType 2 4) 

這裡,我們將函式fType()的型別設定為int。該函式接受兩個int值並返回一個int值。如果你編譯並執行這段程式碼,它將產生以下輸出:

sh-4.3$ ghc -O2 --make *.hs -o main -threaded -rtsopts 
sh-4.3$ main
20

Integer

Integer 可以被視為Int的超集。此值不受任何數字的限制,因此 Integer 可以是任何長度,沒有任何限制。為了瞭解IntInteger型別之間的基本區別,讓我們修改上面的程式碼如下:

fType :: Int -> Int -> Int 
fType x y = x*x + y*y 
main = print (fType 212124454 44545454454554545445454544545)

如果你編譯上面的程式碼,將會丟擲以下錯誤訊息:

main.hs:3:31: Warning:            
   Literal 44545454454554545445454544545 is out of the Int range -
   9223372036854775808..9223372036854775807 
Linking main ...

發生此錯誤是因為我們的函式 fType() 期望一個 Int 型別的值,而我們傳遞了一些非常大的 Int 型別的值。為了避免此錯誤,讓我們用“Integer”修改型別“Int”,並觀察差異。

fType :: Integer -> Integer -> Integer 
fType x y = x*x + y*y 
main = print (fType 212124454 4454545445455454545445445454544545) 

現在,它將產生以下輸出:

sh-4.3$ main
1984297512562793395882644631364297686099210302577374055141

Float

請看下面的程式碼片段。它展示了 Float 型別在 Haskell 中是如何工作的:

fType :: Float -> Float -> Float 
fType x y = x*x + y*y 
main = print (fType 2.5 3.8)

該函式將兩個浮點值作為輸入,併產生另一個浮點值作為輸出。當你編譯並執行此程式碼時,它將產生以下輸出:

sh-4.3$ main
20.689999 

Double

Double 是一個浮點數,在末尾具有雙精度。請看下面的示例:

fType :: Double -> Double -> Double 
fType x y = x*x + y*y 
main = print (fType 2.56 3.81)

當你執行上面的程式碼片段時,它將生成以下輸出:

sh-4.3$ main 
21.0697

Bool

Bool 是布林型別。它可以是 True 或 False。執行以下程式碼以瞭解 Bool 型別在 Haskell 中是如何工作的:

main = do  
   let x = True 
   
   if x == False 
      then putStrLn "X matches with Bool Type" 
   else putStrLn "X is not a Bool Type" 

這裡,我們定義了一個變數“x”作為 Bool,並將其與另一個布林值進行比較以檢查其原始性。它將產生以下輸出:

sh-4.3$ main
X is not a Bool Type 

Char

Char 表示字元。單引號內的任何內容都被視為字元。在下面的程式碼中,我們修改了之前的fType()函式以接受 Char 值並返回 Char 值作為輸出。

fType :: Char-> Char 
fType x = 'K' 
main = do  
   let x = 'v' 
   print (fType x) 

上面的程式碼片段將使用'v'的char值呼叫fType()函式,但它返回另一個 char 值,即'K'。以下是它的輸出:

sh-4.3$ main 
'K'

請注意,我們不會顯式地使用這些型別,因為 Haskell 足夠智慧,可以在宣告之前捕獲型別。在本教程的後續章節中,我們將看到不同的型別和型別類是如何使 Haskell 成為一種強型別語言的。

EQ 型別類

EQ 型別類是一個介面,它提供測試表達式相等性的功能。任何想要檢查表示式相等性的型別類都應該是此 EQ 型別類的一部分。

上面提到的所有標準型別類都是此EQ類的一部分。無論何時我們使用上面提到的任何型別檢查任何相等性,我們實際上都在呼叫EQ型別類。

在下面的示例中,我們使用“==”或“/=”運算在內部使用EQ型別。

main = do 
   if 8 /= 8 
      then putStrLn "The values are Equal" 
   else putStrLn "The values are not Equal"

它將產生以下輸出:

sh-4.3$ main 
The values are not Equal 

Ord 型別類

Ord 是另一個介面類,它為我們提供了排序的功能。到目前為止我們使用過的所有型別都是此Ord介面的一部分。像 EQ 介面一樣,Ord 介面可以使用“>”、“<”、“<=”、“>=”、“compare”進行呼叫。

請在下面找到我們使用此型別類的“compare”功能的示例。

main = print (4 <= 2) 

這裡,Haskell 編譯器將檢查 4 是否小於或等於 2。由於它不是,因此程式碼將產生以下輸出:

sh-4.3$ main 
False

Show

Show 具有將引數列印為字串的功能。無論其引數是什麼,它始終將結果列印為字串。在下面的示例中,我們將使用此介面列印整個列表。“show”可用於呼叫此介面。

main = print (show [1..10]) 

它將在控制檯上產生以下輸出。這裡,雙引號表示它是字串型別的值。

sh-4.3$ main 
"[1,2,3,4,5,6,7,8,9,10]" 

Read

Read 介面與 Show 做相同的事情,但它不會以字串格式列印結果。在下面的程式碼中,我們使用了read介面讀取一個字串值,並將其轉換為 Int 值。

main = print (readInt "12") 
readInt :: String -> Int 
readInt = read 

這裡,我們將一個字串變數(“12”)傳遞給readInt方法,該方法在轉換後返回 12(一個 Int 值)。以下是它的輸出:

sh-4.3$ main 
12

Enum

Enum 是另一種型別的型別類,它在 Haskell 中啟用順序或有序功能。此型別類可以透過Succ、Pred、Bool、Char等命令訪問。

以下程式碼展示瞭如何查詢 12 的後繼值。

main = print (succ 12) 

它將產生以下輸出:

sh-4.3$ main
13

Bounded

所有具有上限和下限的型別都屬於此型別類。例如,Int型別資料具有“9223372036854775807”的最大邊界和“-9223372036854775808”的最小邊界。

以下程式碼展示了 Haskell 如何確定 Int 型別的最大和最小邊界。

main = do 
   print (maxBound :: Int) 
   print (minBound :: Int) 

它將產生以下輸出:

sh-4.3$ main
9223372036854775807
-9223372036854775808

現在,嘗試查詢 Char、Float 和 Bool 型別的最大和最小邊界。

Num

此型別類用於數值運算。Int、Integer、Float 和 Double 等型別屬於此型別類。請看下面的程式碼:

main = do 
   print(2 :: Int)  
   print(2 :: Float) 

它將產生以下輸出:

sh-4.3$ main
2
2.0

Integral

Integral 可以被視為 Num 型別類的子類。Num 型別類包含所有型別的數字,而 Integral 型別類僅用於整數。Int 和 Integer 是此型別類下的型別。

Floating

與 Integral 類似,Floating 也是 Num 型別類的一部分,但它僅包含浮點數。因此,FloatDouble屬於此型別類。

自定義型別類

與任何其他程式語言一樣,Haskell 允許開發人員定義使用者定義的型別。在下面的示例中,我們將建立一個使用者定義的型別並使用它。

data Area = Circle Float Float Float  
surface :: Area -> Float   
surface (Circle _ _ r) = pi * r ^ 2   
main = print (surface $ Circle 10 20 10 ) 

這裡,我們建立了一個名為Area的新型別。接下來,我們使用此型別來計算圓的面積。在上面的示例中,“surface”是一個函式,它將Area作為輸入併產生Float作為輸出。

請記住,“data”在這裡是一個關鍵字,並且 Haskell 中的所有使用者定義型別都以大寫字母開頭。

它將產生以下輸出:

sh-4.3$ main
314.15927
廣告