跳轉到內容

Haskell/庫/Maybe

來自華夏公益教科書,開放書籍,為開放的世界

Maybe 資料型別用於可能不成功的函式。完整的描述在 Maybe 單子 章中。

標準 Prelude 定義 Maybe 型別如下

data Maybe a = Nothing | Just a

回想一下,型別 a 是多型的,可以包含複雜型別,甚至可以包含其他單子(如 IO () 型別)。

庫函式

[編輯 | 編輯原始碼]

標準 分層庫 中的 Data.Maybe 模組包含大量用於處理 Maybe 值的函式。

兩個明顯的函式提供關於 Maybe 值的資訊

isJust 在給定 Just _ 形式的引數時返回 True。

isJust :: Maybe a -> Bool
isJust (Just _) = True
isJust Nothing  = False

isNothing

[編輯 | 編輯原始碼]

isNothing 如果其引數為 Nothing 則返回 True。

isNothing :: Maybe a -> Bool
isNothing (Just _) = False
isNothing Nothing  = True

獲取結果

[編輯 | 編輯原始碼]

有一些函式用於將 Maybe 值轉換為非 Maybe 值。

maybe 將給定函式應用於 Just 傳遞的內部值,但在給定 Nothing 時返回預設值。

maybe :: b -> (a -> b) -> Maybe a -> b
maybe _ f (Just x) = f x
maybe z _ Nothing  = z

fromMaybe

[編輯 | 編輯原始碼]

我們可能希望在不將任何函式應用於 Just 的情況下使用 maybe。我們可以透過使用函式 id 呼叫 maybe 來做到這一點。Data.Maybe 已經有了這個,叫做 fromMaybe

fromMaybe :: a -> Maybe a -> a
fromMaybe z = maybe z id

注意使用無點風格。maybe z id 評估為一個函式,它可以接受 Maybe 值。

列表和 Maybe

[編輯 | 編輯原始碼]

列表和 Maybe 之間的許多相似之處在 列表單子 章中討論。鑑於這些聯絡,有一些函式可以在這兩者之間轉換

listToMaybe

[編輯 | 編輯原始碼]

失敗的計算返回列表的 [] 和 Maybe 的 NothinglistToMaybe 從列表轉換為 Maybe 單子。由於 Maybe 只能容納一個值,listToMaybe 僅從列表中獲取第一個解決方案。

listToMaybe :: [a] -> Maybe a
listToMaybe []    = Nothing
listToMaybe (x:_) = Just x

maybeToList

[編輯 | 編輯原始碼]

當然,listToMaybe 的反向是 maybeToList

maybeToList :: Maybe a -> [a]
maybeToList Nothing  = []
maybeToList (Just x) = [x]

列表操作

[編輯 | 編輯原始碼]

有一些函式類似於普通的 Prelude 列表操作函式,但專門針對 Maybe 值。

繼續處理部分失敗

[編輯 | 編輯原始碼]

我們可能希望有一個 OR 函式,它不會因為一個部分失敗而使整個計算失敗。

catMaybes
[編輯 | 編輯原始碼]

給定一個 Maybe 值列表,catMaybes 提取所有 Just _ 形式的值,並剝離 Just 建構函式。列表推導在這裡完成了這項工作(正如我們在 模式匹配 章中所展示的那樣)。

catMaybes :: [Maybe a] -> [a]
catMaybes ms = [ x | Just x <- ms ]

mapMaybe 將函式應用於列表並收整合功的結果。它可以理解為已知函式的組合

mapMaybe :: (a -> Maybe b) -> [a] -> [b]
mapMaybe f xs = catMaybes (map f xs)

然而,Data.Maybe 中的實際定義遍歷列表,效率可能更高

mapMaybe :: (a -> Maybe b) -> [a] -> [b]
mapMaybe _ []     = []
mapMaybe f (x:xs) = 
  case f x of
    Just y  -> y : mapMaybe f xs
    Nothing -> mapMaybe f xs

失敗時停止

[編輯 | 編輯原始碼]

與其說是 OR,不如說是當且僅當所有都成功時才收集值。

sequence :: [Maybe a] -> Maybe [a]
sequence []           = Just []
sequence (Nothing:xs) = Nothing
sequence (Just x:xs)  = case sequence xs of
  Just xs' -> Just (x:xs')
  _        -> Nothing
華夏公益教科書