好吧,我真正想做的是,我有一个数组,我想从中选择一个随机元素.显而易见的是从0和长度减1之间的随机数生成器获取一个整数,我已经工作了,然后应用Array.get,但返回一个Maybe a
.(似乎还有一个包函数可以做同样的事情.)来自Haskell,我得到的类型意义是它保护我免受我的索引超出范围的情况,但我控制了索引而不是期待这种情况发生,所以我只想假设我得到了Just
一些东西并且有点强行转换为a
.在哈斯克尔fromJust
,如果我感到冗长,那将是或者fromMaybe (error "some message")
.我应该怎么做榆树?
我在邮件列表上发现了一个似乎正在讨论这个问题的讨论,但它已经有一段时间了,我没有在标准库中看到我想要的功能,而讨论表明它会是这样.
以下是我发现的一些非常不满意的潜在解决方案:
a
available,但我不喜欢这个,因为它给我的代码带来了完全错误的含义,并且可能会使调试变得更加困难.(回答我自己的问题)
我发现了两个更令人满意的解决方案:
模式匹配并使用Debug.crash,如果它是Nothing.这似乎与Haskell类似error
,是我现在倾向于的解决方案.
import Debug
fromJust : Maybe a -> a
fromJust x = case x of
Just y -> y
Nothing -> Debug.crash "error: fromJust Nothing"
Run Code Online (Sandbox Code Playgroud)
(尽管如此,模块名称和描述也让我犹豫不决,因为它看起来似乎不是用于我的目的的"正确"方法;我想指出真正的程序员错误而不仅仅是调试.)
某个函数或等效函数的存在或使用fromJust
实际上是代码味道,它会告诉您 API 的设计不正确。问题在于,您在获得执行该操作的信息之前就试图做出该做什么的决定。您可以在两种情况下考虑这一点:
如果您知道应该用 做什么Nothing
,那么解决方案很简单:使用withDefault
。当您查看代码中的正确位置时,这一点会变得显而易见。
如果您不知道在这种情况下应该做什么Nothing
,但您仍然想做出改变,那么您需要采用不同的方法。Maybe
而不是从使用中拉出值Maybe.map
来更改值,同时保留Maybe
. 举个例子,假设您正在执行以下操作:
foo : Maybe Int -> Int
foo maybeVal =
let
innerVal = fromJust maybeVal
in
innerVal + 2
Run Code Online (Sandbox Code Playgroud)
相反,你会想要这个:
foo : Maybe Int -> Maybe Int
foo maybeVal =
Maybe.map (\innerVal -> innerVal + 2) maybeVal
Run Code Online (Sandbox Code Playgroud)
请注意,在这种情况下,您想要的更改仍然完成,您只是没有处理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
Run Code Online (Sandbox Code Playgroud)
事实证明,即使在这种情况下,也有一些干净的方法可以避免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
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
3262 次 |
最近记录: |