2017-07-02 3 views
0

Ich habe Makros in Elixir untersucht und dann habe ich dieses Snippet gefunden in Programmierung Elixir> Kapitel 20> Verwenden von Bindungen, um Werte zu injizieren.Dynamische Funktionsdefinition mit unquote

defmodule Test do 
    require My 
    [ :fred, :bert ] |> Enum.each(&My.mydef(&1)) 
end 

In der mydef ist ein einfaches Makro, das für den Vornamen eine Echomethode definiert. So sollte mein Modul-Test haben zwei Funktionen fred und bert, dann erklärt der Autor bind_quoted, und es verwendet unquote innerhalb der Makro, um die Funktion zu definieren, in Folge hat.

defmodule My do 
    defmacro mydef(name) do 
    quote bind_quoted: [name: name] do 
     def unquote(name)(), do: unquote(name) 
    end 
    end 
end 

Der Autor hat gesagt, dass bind_quoted die aufschieben würde unquote Ausführung, damit die Methoden zur Laufzeit definiert werden können. Dann habe ich Macro.to_string verwendet, um zu analysieren, was erzeugt wurde, was mich darauf hinweist, dies zu testen.

defmodule Test do 
    name = :something 
    def unquote(name)(), do: unquote(name) 
end 

Test.something() 
# Returns :something 

Jetzt frage ich mich, wie das funktioniert. Dieser Code sollte einen Fehler auslösen, der besagt, dass unquote nicht innerhalb eines quote Blocks verwendet wird, und fast dasselbe für Makro mydef, das laut Elixir-Dokumentation unquote bei Verwendung von bind_quoted nicht verwenden kann.

Kann jemand erklären, wie Elixir diesen Code behandelt?

+0

Ich hatte gedacht, dass es war, weil 'def 'ein Makro ist, dann vorausgesetzt, dass Makroparameter vor dem Übergeben an das Makro selbst zitiert werden, so würde" unquote "erlaubt sein. Aber wenn ich 'My.mydef (unquote (name))' versuche, dann bekomme ich den erwarteten Fehler. Ich denke, dass es einen speziellen Umgang mit Def-Parametern gibt. –

+0

Das ist wahr, wir können unquote auf Makro-Parameter verwenden, aber um den Wert dieses Parameters zu erhalten, müssen wir den zitierten Ausdruck ausschließen, um Aufrufe in "unquote" mit "Macro.escape (expr, unquote: true)" zu entfernen . Dann können wir einen neuen Ausdruck "zitieren", der unseren geflüchteten zitierten Ausdruck verwendet. Wir müssen jedoch daran denken, den Ausdruck zu "löschen", um seinen Wert in den Kontext des Aufrufers einzufügen, was für 'unquote (name)' als Parameter der Bezeichner 'name' ist. –

+0

Ich könnte diese Frage beantworten, wenn Sie bitte eine einzige Frage, formatiert. Bitte entfernen Sie eine Antwort, die auf keinen Fall eine Antwort ist, entfernen Sie Kommentare, fügen Sie die wesentlichen Teile sowohl der Antwort als auch der Kommentare in die ursprüngliche Frage ein und machen Sie sie zu [MCVE] (https://stackoverflow.com/help/mcve). – mudasobwa

Antwort

0

Ich denke, dass der Autor gesagt hat, dass Macro.escape nicht zu erklären, es bind_quoted verwendet, um eine Variable zu binden und unquote zur gleichen Zeit zu deaktivieren. Weil, zumindest weiß ich nicht wie, das Deaktivieren von Ansätzen nur für einige Teile unserer Makros nicht möglich ist, dann musste das getan werden. Da Makroparameter zitiert werden, bevor sie an das Makro übergeben werden, können wir alles verwenden, was wir wollen, aber unquote wird davon abhängen, wie das Makro das handhabt, d. e., wirft dieser Code einen Fehler, wenn wir unquote in params verwenden

defmacro print(str) do 
    quote do 
    IO.puts unquote(str) 
    end 
end 

print("Hello World") 
# => :ok 
str = "Hello again" 
print(unquote(str)) 
# => unquote cannot be used outside quote 

Den zweiten Aufruf von IO.puts(unquote(str)) erweitert würde zu drucken und es ist unser Fehler. Um das zu umgehen, müssen wir der Unquote für den Parameter entkommen, wie es in Kernel.def gemacht wurde - benutze Macro.escape (expr, unquote: true).

Verwandte Themen