解决方案
一个或等效函数的存在或使用fromJust
实际上是代码异味,并告诉您该 API 设计不正确。问题是你试图在获得信息之前就决定要做什么。您可以在两种情况下考虑这一点:
如果你知道你应该做什么Nothing
,那么解决方案很简单:使用withDefault
. 当您查看代码中的正确点时,这将变得显而易见。
如果你不知道在你拥有的情况下应该做什么Nothing
,但你仍然想做出改变,那么你需要一种不同的方式来做到这一点。而不是Maybe
在Maybe.map
保留Maybe
. 例如,假设您正在执行以下操作:
foo : Maybe Int -> Int
foo maybeVal =
let
innerVal = fromJust maybeVal
in
innerVal + 2
相反,你会想要这个:
foo : Maybe Int -> Maybe Int
foo maybeVal =
Maybe.map (\innerVal -> innerVal + 2) maybeVal
请注意,您想要的更改在这种情况下仍然完成,您根本没有处理您拥有Nothing
. 您现在可以在调用链上上下传递这个值,直到找到一个可以自然地withDefault
用来摆脱Maybe
.
发生的情况是,我们将“如何更改此值”和“当它不存在时我该怎么办?”的关注点分开。我们用 处理前者Maybe.map
,用 处理后者Maybe.withDefault
。
警告
在少数情况下,您只是知道自己有一个Just
价值并需要fromJust
按照您的描述使用它来消除它,但这些情况应该很少见。有很多实际上有一个更简单的选择。
示例:尝试过滤列表并获取值。
假设您有一个Maybe
想要其值的 s 列表。一个常见的策略可能是:
foo : List (Maybe a) -> List a
foo hasAnything =
let
onlyHasJustValues = List.filter Maybe.isJust hasAnything
onlyHasRealValues = List.map fromJust onlyHasJustValues
in
onlyHasRealValues
事实证明,即使在这种情况下,也有一些干净的方法可以避免fromJust
. 大多数具有包含映射和过滤器的集合的语言都有一种使用Maybe
内置过滤器的方法。Haskell 有Maybe.mapMaybe
,Scala 有flatMap
,Elm 有List.filterMap
。这会将您的代码转换为:
foo : List (Maybe a) -> List a
foo hasAnything =
let
onlyHasRealValues = List.filterMap (\x -> x) hasAnything
in
onlyHasRealValues