iT邦幫忙

2023 iThome 鐵人賽

DAY 15
0
Software Development

Haskell 從入門到放棄系列 第 15

[Haskell 從入門到放棄] Day 15 - Algebraic Data Types (2)

  • 分享至 

  • xImage
  •  

Sum Type

我們先來看一下 Bool 在 Haskell 是如何被定義的

data Bool = False | True deriving  (Read, Show, Eq, Ord, Enum, Bounded)

這裡會看到 FalseTrue 中間不是空格而是 | ,其實就跟 or 的概念有點像,也就代表 Bool 不是 False 就是 True ,這種非 a type不然就是 b type 的形式就很適合使用 sum type 來實現。

那至於為什麼是 sum ,很明顯的因為他不是 True 不然就是 False 總共是 1 + 1 種可能的狀態,所以稱為 sum type

稍微組合一下

那假設我們想要表示一個data type 叫做 Shape 且它包含了三角形與四邊形,我們可以這樣定義

data Shape = Triangle Double Double Double | Rectangle Double Double Double Double deriving (Show)

我們可以將 sum type 與 product type 輕鬆地組合起來

使用起來會像是這樣

t = Triangle 1.0 2.0 2.0
r = Rectangle 1.0 1.0 1.0 1.0

t -- Triangle 1.0 2.0 2.0
r -- Rectangle 1.0 1.0 1.0 1.0

:t t -- t :: Shape
:r r -- r :: Shape

看起來就跟我們分開定義 product type 一樣直到最後的 :t ,雖然他們分別是用 TriangleRectangle 這兩個不一樣的 value constructor 建造出來,但他們依然屬於同一個 type Shape ,那就算我們知道這點我們可以怎麼運用?

舉個例子,假設我們想要寫出一個 function 是計算 Shape 的周長的話可以利用 Shape 來限制這個 function type。

surface :: Shape -> Double
surface (Triangle a b c) = a + b + c
surface (Rectangle a b c d) = a + b + c + d 

print $ surface $ Triangle 3.0 4.0 5.0 -- 12.0
print $ surface $ Rectangle 4.0 4.0 4.0 4.0 -- 16.0

會看到我們這個 function 的 type 既不是 Triangle 也不是 Rectangle 或者該說是什麼都不重要只要知道是 Shape 就好,至於遇到 Triangle 或者 Rectangle 該怎麼計算就交給 pattern matching 。

會發現 sum type 配合 pattern matching 十分的舒服,我只要匹配到是 Triangle ,我就知道我要怎麼做。

Type Parameters

簡單來說就是 type(精確來說是 value constructor )有了參數,然後藉此來產生一個新的type 。我們從 Haskell 內建的一個 type 來看

data Maybe a = Nothing | Just a

這裡的 a 就是就是所謂的 type Parameter,也就是我們之前很常看到的 Num a => a 裡面的 a 是一樣的意思。

稍微回憶一下 Num a => a 就是 a 的 type 必須是 Num 這個 type class 的一員。

用起來會像是這樣


parseToInt :: String -> Maybe Int
parseToInt str =
  case reads str of
    [(x, "")] -> Just x 
    _         -> Nothing 

main :: IO ()
main = do
  putStrLn "input a integer:"
  input <- getLine
  case parseToInt input of
    Just num -> putStrLn $ "output " ++ show num
    Nothing  -> putStrLn "invalid input"

先忽略還沒介紹的語法的話,我們主要的重點會是在 parseToInt :: String -> Maybe Int 以及 case parseToInt input of 及後面的兩行 pattern matching 。

首先我們實作一個 function parseToInt 來作為將輸入的字串轉為 Int 這件事情,但我們無法保證使用者一定會輸入 Int 所以我們只能先使用 Maybe Int 然後根據使用者的輸入而回傳 Just x 或者 Nothing

之後在利用 pattern matching 如果是匹配到 Just num 那我們當然就能直接輸出這個數字,而且我們也能匹配到使用者錯誤的輸入


今天的程式碼:https://github.com/toddLiao469469/30days-for-haskell


上一篇
[Haskell 從入門到放棄] Day 14 - Algebraic Data Types (1)
下一篇
[Haskell 從入門到放棄] Day 16 - Algebraic Data Types (3)
系列文
Haskell 從入門到放棄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言