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 如果其参数为 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
我们可能希望在不将任何函数应用于 Just 的情况下使用 maybe。我们可以通过使用函数 id 调用 maybe 来做到这一点。Data.Maybe 已经有了这个,叫做 fromMaybe
fromMaybe :: a -> Maybe a -> a
fromMaybe z = maybe z id
注意使用无点风格。maybe z id 评估为一个函数,它可以接受 Maybe 值。
列表和 Maybe 之间的许多相似之处在 列表单子 章中讨论。鉴于这些联系,有一些函数可以在这两者之间转换
失败的计算返回列表的 [] 和 Maybe 的 Nothing。listToMaybe 从列表转换为 Maybe 单子。由于 Maybe 只能容纳一个值,listToMaybe 仅从列表中获取第一个解决方案。
listToMaybe :: [a] -> Maybe a
listToMaybe []    = Nothing
listToMaybe (x:_) = Just x
当然,listToMaybe 的反向是 maybeToList
maybeToList :: Maybe a -> [a]
maybeToList Nothing  = []
maybeToList (Just x) = [x]
有一些函数类似于普通的 Prelude 列表操作函数,但专门针对 Maybe 值。
我们可能希望有一个 OR 函数,它不会因为一个部分失败而使整个计算失败。
给定一个 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
