【问题标题】:Elixir behavior when guards fail in case expressions当守卫在 case 表达式中失败时的 Elixir 行为
【发布时间】:2017-11-30 00:50:38
【问题描述】:

为什么case 在防护失败时不抛出运行时异常,而是静默失败从而隐藏潜在的错误?

例如为什么

case [] do
   xs when hd(xs) -> "Won't match"
   xs -> "Got #{xs}"
end

不会因为hd(xs)失败而返回参数错误?

更新:我提出这个问题是因为 Haskell 中的守卫不会发生同样的情况。比如函数

myfun x
  | head([]) == x = 100
  | otherwise = 200

在 GHCi 中调用时会产生

λ> myfun 6
*** Exception: Prelude.head: empty list

简而言之,与不对程序员隐藏异常的 Haskell 相比,Elixir 吃守卫中异常的行为背后的设计原理是什么?

谢谢,

【问题讨论】:

  • 因为这是警卫的工作方式。如果它提出,这个案子永远不会作为案子。如果您想引发异常,请使用直接模式匹配。
  • @mudasobwa 充当case 是什么意思?对我来说,在程序中伪装错误的东西是语言的设计缺陷。
  • 根据您的逻辑,所有允许救援异常的语言都有设计流程。它不会伪装任何东西。它显式地捕获任何可能的异常并返回false。这使得守卫更简洁,这是完美的。这是一个守卫,而不是一段随机的代码。 对你来说,它似乎是一个设计流程,与现实中存在的设计流程无关。
  • @mudasobwa 不,不,这不是明确的捕获,而是隐含的捕获。如果你的程序在一个守卫之外访问一个空列表的头部并且语言会像 Elixir 那样为你抛出一个运行时异常,你是否不考虑一个错误?或者你更喜欢在这种情况下获得零并继续前进?如果 Elixir 在守卫之外抛出异常,它在守卫内部的行为应该与此一致。
  • “守卫内部的行为应该与此保持一致” — 真的吗?这是为什么?因为你不熟悉guardsguard 的捕获是一个明确的捕获,正如文档中到处都清楚地说明的那样。这是一个契约:rescueguard 都是显式捕获。忍受它:)

标签: erlang elixir


【解决方案1】:

任何由守卫函数引发的错误都会被忽略,并且匹配被认为是不成功的。这记录在http://erlang.org/doc/reference_manual/expressions.html#id84741

如果算术表达式、布尔表达式、短路表达式或对保护 BIF 的调用失败(由于参数无效),则整个保护失败。如果守卫是守卫序列的一部分,则评估序列中的下一个守卫(即下一个分号后面的守卫)。

【讨论】:

  • 我的问题不是它是如何工作的,而是为什么它会这样工作。对我来说,这似乎是一个设计缺陷,让程序员有机会默默地忽略他们的错误。语言中的这种行为有什么充分的理由吗?
猜你喜欢
  • 1970-01-01
  • 2015-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-15
  • 2011-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多