【问题标题】:Elixir macro with guard clause not working as expected for negative values对于负值,带有保护子句的 Elixir 宏不能按预期工作
【发布时间】:2022-11-22 09:16:28
【问题描述】:

为什么以下 Elixir 宏不适用于负值?

代码非常简单,没什么特别的,只有一个带有一些简单保护子句的宏:

defmodule IntegerChecker do
  defmacro is_negative_or_zero(number)
    when is_integer(number) and number <= 0, do: true
  
  defmacro is_negative_or_zero(number)
    when is_integer(number), do: false
end
> import IntegerChecker

> is_negative_or_zero(0)
true

> is_negative_or_zero(1)
false

> is_negative_or_zero(20)
false

> is_negative_or_zero(-1)
** (FunctionClauseError) no function clause matching in IntegerChecker.is_negative_or_zero/1
    expanding macro: IntegerChecker.is_negative_or_zero/1

【问题讨论】:

    标签: elixir


    【解决方案1】:

    因为您定义的是宏而不是函数,所以要传递的参数是 AST,而不是值。

    • 函数:在运行时传递值
    • 宏:在编译时传递 AST

    所以 number 将成为 -1 的 AST,您可以使用 quote/2 进行检查:

    iex(1)> quote do: -1
    {:-, [context: Elixir, imports: [{1, Kernel}, {2, Kernel}]], [1]}
    iex(2)> quote do: 1
    1
    

    1 不同,表示 -1 的 AST 是一个元组,而不是整数本身。

    在您的情况下,您可能想要使用常规函数(如果您想在非数字情况下提高)或 guard(不会提高):

    defguard is_negative_or_zero(number) when is_integer(number) and number <= 0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-02-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-16
      • 2019-08-27
      相关资源
      最近更新 更多