跳转到内容

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
华夏公益教科书