摘要
探讨 Elixir 中一个令人惊讶的行为:`is_map_key/2` 守卫可能导致守卫失败而非返回 false,从而破坏了布尔运算符的可交换性。
<p><a href="https://lobste.rs/s/b2emi7/guards_guards">评论</a></p>
查看缓存全文
缓存时间:
2026/06/27 17:55
# Hauleth 的博客 - 守卫!守卫!
来源:https://hauleth.dev/post/guards-guards/
我们先从一个简单的小测开始。
---
给定如下模块定义:
```elixir
defmodule Foo do
def a(x) when is_integer(x) or is_map_key(x, :foo), do: true
def a(x), do: false
def b(x) when is_map_key(x, :foo) or is_integer(x), do: true
def b(x), do: false
end
```
试着回答以下问题。
**问:** `Foo.a(%{foo: 21})` 的结果是什么?
`true`
`false`
错误
正确
这个问题很直白。
我们检查守卫,它有一个条件 `is_integer(x) or is_map_key(x, :foo)`。第一个返回 `false`,第二个返回 `true`,布尔运算的或运算结果为 `true`,因此匹配第一个子句。
**问:** `Foo.a(37)` 的结果是什么?
`true`
`false`
错误
正确
这个问题同样直白。
我们检查守卫,它有一个条件 `is_integer(x) or is_map_key(x, :foo)`。第一个返回 `true`,第二个根本不会触发,因为 `or` 运算符是短路的。
**问:** `Foo.b(%{foo: 21})` 的结果是什么?
`true`
`false`
错误
正确
同样,和前几个问题类似。
我们检查守卫,它有一个条件 `is_map_key(x, :foo) or is_integer(x)`。第一个返回 `true`,剩余部分被短路。
**问:** `Foo.b(37)` 的结果是什么?
`true`
`false`
错误
正确
哦,出现了变化……
我们再次检查守卫,一个条件 `is_map_key(x, :foo) or is_integer(x)`。我们首先遇到第一个子句 `is_map_key(x, :foo)`,而这个子句 **没有** 返回 `false`,相反它失败了。守卫函数中的任何一个失败都不会转换为 `false`,而是导致整个守卫表达式失败。这意味着 `is_integer(x)` 部分将 **永远不会** 被调用。
---
这种行为常常让许多 Elixir 开发者感到惊讶,因为它似乎破坏了布尔运算符的交换律。然而,说实话,由于短路求值的缘故,它们从来就不是可交换的。
似乎在撰写本文时(Elixir 1.20.1,OTP 29),Elixir 并未对此问题发出警告。
∎
相似文章
The Old New Thing (Raymond Chen)
一位开发者发现,交换两个等效宏竟导致无关函数中出现意外的整数变化,这篇博客文章深入探究了这一谜团,并对某个大语言模型(LLM)关于控制流保护的解释提出了质疑。
Hacker News Top
一篇后续文章,展示了各种‘molly guards’的例子——这些是防止意外按键或操作的物理和软件设计元素——从IBM打字机到Chrome的退出对话框。
Hacker News Top
Clojure 1.13.0-alpha1 已发布,新增了用于映射解构的检查键,强制要求必需键并在缺失时抛出异常,以及其他改进。
Hugging Face Daily Papers
# Paper page - PrefixGuard: From LLM-Agent Traces to Online Failure-Warning Monitors Source: [https://huggingface.co/papers/2605.06455](https://huggingface.co/papers/2605.06455) ## Abstract PrefixGuard enables effective online monitoring of LLM agents through trace analysis and prefix\-based risk scoring, demonstrating strong performance across multiple benchmark tasks while providing diagnostic insights for alert reliability\. Large language model \(LLM\) agents now execute long, tool\-using ta
X AI KOLs Following
一位开发者分享了这样一个经历:OpenAI的Codex在API中插入了一个运行时扩展存在性检查,这是一种过多的防护措施,人类工程师绝不会这样做。