我們先來看一下 Bool
在 Haskell 是如何被定義的
data Bool = False | True deriving (Read, Show, Eq, Ord, Enum, Bounded)
這裡會看到 False
跟 True
中間不是空格而是 |
,其實就跟 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
,雖然他們分別是用 Triangle
跟 Rectangle
這兩個不一樣的 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(精確來說是 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