(デイブ・トーマスの優れたProgramming Elixir 1.2、チャプター21)をハングし、私は何が起こっているの私の理解では、バンプのビットをヒットしました。実行時にはUnquoting引数は、私はマクロの行使により取り組んできた関数呼び出し
defmodule Test do
import Kernel, except: [def: 2]
import Tracer, only: [def: 2]
def puts_sum_three(a, b, c), do: IO.inspect(a+b+c)
def add_list(list), do: Enum.reduce(list, 0, &(&1 + &2))
def neg(a) when a < 0, do: -a
end
:
defmodule Tracer do
def dump_args(args) do
args |> Enum.map(&inspect/1) |> Enum.join(",")
end
def dump_defn(name, args) do
"#{name}(#{dump_args(args)})"
end
defmacro def({name, _, args} = definition, do: content) do
IO.puts("Definition: #{inspect definition}")
IO.puts("Content: #{inspect content}")
quote do
Kernel.def unquote(definition) do
IO.puts("==> call: #{Tracer.dump_defn(unquote(name), unquote(args))}")
result = unquote(content)
IO.puts("<== resp: #{inspect result}")
result
end
end
end
end
とTest
は、その使用を示すために、このマクロを使用しています。私はTracer
は次のように呼び出しと応答のロギングを挿入するマクロdef
を再定義する二つのモジュール、Tracer
とTest
を、持っていますこれは、最初の2つの関数が期待通りに機能します。
iex(3)> Test.puts_sum_three(1,2,3)
==> call: puts_sum_three(1,2,3)
6
<== resp: 6
6
iex(4)> Test.add_list([1,2,3,4])
==> call: add_list([1, 2, 3, 4])
<== resp: 10
10
ただし、3番目の関数ハングしているように見える - 具体的にはunquote(args)
でハング:
iex(5)> Test.neg(-1)
だから私の質問は、ハングアップしたようにNEGの呼び出しを引き起こすもの、ですか?私はアイデアを持っていると思うが、私はそれがなぜそうするのかを理解する(あるいは反論する)ことを望む。
第3の関数のwhen
句は、def
マクロに渡される引用された式の表現を変更し、これを処理するためのマクロの再加工に問題はありません。 neg
のために渡されdefinition
とcontent
は、次のとおりです。私たちはneg
でunquote(args)
に到達すると、
Definition: {:when, [line: 7], [{:neg, [line: 7], [{:a, [line: 7], nil}]}, {:<, [line: 7], [{:a, [line: 7], nil}, 0]}]}
Content: {:-, [line: 7], [{:a, [line: 7], nil}]}
args
式を評価しようとしている私はneg
への呼び出しを含むリストであると考えていると、無限再帰的に結果ループ。これは正しいです?どのように私がこれをデバッグ/診断するかもしれないかについての指針は、さらに読むことへのリンクと同様に評価されるだろう。
おかげで、あなたの提案します修正は実際にどのように私はそれの周りに働いたので、私は何が起こっているのか理解し始めているいくつかの自信を与える! – Taufiq