Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Macros 在Elixir宏中使用防护装置_Macros_Elixir - Fatal编程技术网

Macros 在Elixir宏中使用防护装置

Macros 在Elixir宏中使用防护装置,macros,elixir,Macros,Elixir,我正在研究宏,它将采用一个函数并添加一些附加功能。例如: 这: 应转换为: def this_works(a, b) do IO.puts("LOGGING whatever") a + b + 1 end 这就是我目前所拥有的。尝试在iex中运行这段代码: defmodule MyMacro do defmacro defstate(ast, do: block) do {fn_atom, _} = Macro.decompose_call(a

我正在研究宏,它将采用一个函数并添加一些附加功能。例如:

这:

应转换为:

  def this_works(a, b) do
    IO.puts("LOGGING whatever")
    a + b + 1
  end
这就是我目前所拥有的。尝试在iex中运行这段代码:

  defmodule MyMacro do
    defmacro defstate(ast, do: block) do
      {fn_atom, _} = Macro.decompose_call(ast)

      quote do
        def unquote(fn_atom)(var!(a), var!(b)) do
          IO.puts("LOGGING")
          unquote(block)
        end
      end
    end
  end

  defmodule Test1 do
    import MyMacro

    defstate this_works(a, b) do
      a + b + 1
    end
  end

  Test.this_works(1, 2)
这正如预期的那样有效

现在,此模块不编译:

  defmodule Test2 do
    import MyMacro

    defstate this_fails(a, b) 
      when 1 < 2 
      when 2 < 3 
      when 3 < 4 do
      a + b + 1
    end
  end
唯一的变化是我添加了一个保护,宏无法处理这个问题

如何改进MyMacro.defstate,使其与具有任意数量保护的函数一起工作?

如果您使用defstate this\u fails a,b当1<2时检查fn\u atom,您将看到它是:when而不是:this\u fails。这是因为表达式在Elixir AST中的表示方式:

iex(1)> quote do
...(1)>   def foo, do: 1
...(1)> end
{:def, [context: Elixir, import: Kernel],
 [{:foo, [context: Elixir], Elixir}, [do: 1]]}
iex(2)> quote do
...(2)>   def foo when 1 < 2, do: 1
...(2)> end
{:def, [context: Elixir, import: Kernel],
 [{:when, [context: Elixir],
   [{:foo, [], Elixir}, {:<, [context: Elixir, import: Kernel], [1, 2]}]},
  [do: 1]]}
我还更改了def之后的unquote,以确保保留when子句。

如果使用defstate this\u fails a,b当1<2时检查fn\u atom,您将看到它是:when而不是:this\u fails。这是因为表达式在Elixir AST中的表示方式:

iex(1)> quote do
...(1)>   def foo, do: 1
...(1)> end
{:def, [context: Elixir, import: Kernel],
 [{:foo, [context: Elixir], Elixir}, [do: 1]]}
iex(2)> quote do
...(2)>   def foo when 1 < 2, do: 1
...(2)> end
{:def, [context: Elixir, import: Kernel],
 [{:when, [context: Elixir],
   [{:foo, [], Elixir}, {:<, [context: Elixir, import: Kernel], [1, 2]}]},
  [do: 1]]}
我还更改了def之后的unquote,以确保保留when子句。

对defstate的调用在编译时从defmacro扩展到quote块中的内容。因此,保护表达式不会直接应用于宏调用,因为在编译时,内部定义的函数不会被调用

因此,您必须抓取:当您自己对元组进行分组并自己添加防护:

defmodule MyMacro do
  defmacro defstate({:when, _, [ast, guards]}, do: block) do
    {fn_atom, _} = Macro.decompose_call(ast)

    quote do
      def unquote(fn_atom)(var!(a), var!(b)) when unquote(guards) do
        IO.puts("LOGGING")
        unquote(block)
      end
    end
  end
end
请注意我现在如何匹配{:when,{ast,guards]}元组

当使用保护调用宏时,它会将原始ast放在参数列表的第一项中,将保护表达式放在第二项中

请注意,如果要在不使用保护子句的情况下使用宏,您仍然必须在下面定义一个“捕获所有”宏定义。

对defstate的调用在编译时从defsmacro扩展到quote块中的内容。因此,保护表达式不会直接应用于宏调用,因为在编译时,内部定义的函数不会被调用

因此,您必须抓取:当您自己对元组进行分组并自己添加防护:

defmodule MyMacro do
  defmacro defstate({:when, _, [ast, guards]}, do: block) do
    {fn_atom, _} = Macro.decompose_call(ast)

    quote do
      def unquote(fn_atom)(var!(a), var!(b)) when unquote(guards) do
        IO.puts("LOGGING")
        unquote(block)
      end
    end
  end
end
请注意我现在如何匹配{:when,{ast,guards]}元组

当使用保护调用宏时,它会将原始ast放在参数列表的第一项中,将保护表达式放在第二项中


请注意,如果您想在不使用保护子句的情况下使用宏,您仍然必须在下面定义一个“全包”宏定义。

您的答案更好:这几乎是好的。然而,我的问题是如何使这个宏与具有任意数量保护的函数一起工作:我可以对macro.decompose_callast的结果进行一些复杂的递归模式匹配。然而,我正在寻找更简单更容易的方法来实现这一点。你说的任何数量的警卫是什么意思?一个函数只能有一个防护装置。@为什么上面的方法对它很有效,你可以自己检查一下。第二个when是and的别名。是的!一切正常。谢谢你的答案更好:这几乎是好的。然而,我的问题是如何使这个宏与具有任意数量保护的函数一起工作:我可以对macro.decompose_callast的结果进行一些复杂的递归模式匹配。然而,我正在寻找更简单更容易的方法来实现这一点。你说的任何数量的警卫是什么意思?一个函数只能有一个防护装置。@为什么上面的方法对它很有效,你可以自己检查一下。第二个when是and的别名。是的!一切正常。谢谢
defmodule MyMacro do
  defmacro defstate({:when, _, [ast, guards]}, do: block) do
    {fn_atom, _} = Macro.decompose_call(ast)

    quote do
      def unquote(fn_atom)(var!(a), var!(b)) when unquote(guards) do
        IO.puts("LOGGING")
        unquote(block)
      end
    end
  end
end