2015-08-08 15 views
6

Tại sao Elixir báo cáo UndefinedFunctionError khi gọi macro bằng cú pháp Module.macroName trong tệp .exs? Tôi dường như có thể gọi Macro chỉ khi tôi có một chức năng khác gọi macro và tôi gọi hàm thay vì macro.Elixir - Gọi/Gọi macro - Không xác địnhFunctionError

Dưới đây đang chứng tỏ điều này:

defmodule Sample do 
    defmacro doIt(expression) do 
    quote do 
     IO.puts unquote(expression) 
    end 
    end 

    def doFunc(e), do: doIt(e) 
end 

Sample.doFunc "Hello World via Function" # Works fine 
Sample.doIt "Hello World from Macro!" # Gives error 

Output

Hello World via Function 
** (UndefinedFunctionError) undefined function: Sample.doIt/1 
    Sample.doIt("Hello World from Macro!") 
    (elixir) lib/code.ex:307: Code.require_file/2 

Ví dụ Elixir documentation sử dụng iex, thay vì gọi vĩ mô trong file .exs. Ngay cả trên mã, nếu chúng ta loại bỏ các cuộc gọi đến Sample.doIt và tải nó trong iex, và sau đó gọi Sample.doIt hoạt động tốt.

E:\elixir>iex hello.exs 
Hello World via Function 
Interactive Elixir (1.0.4) - press Ctrl+C to exit (type h() ENTER for help) 
iex(1)> require Sample 
nil 
iex(2)> Sample.doIt "Hello" 
Hello 
:ok 
iex(3)> 

Nếu tôi cố gắng require Sample trong hồ sơ của tôi ở trên, như dưới đây

defmodule Sample 
    ... rest of stuff as shown above ... 
end 

require Sample 

Sample.doFunc "Hello World via Function" 
Sample.doIt "Hello World from Macro!" 

tôi nhận được lỗi

** (CompileError) hello.exs:11: module Sample is not loaded but was defined. This happens because you are trying to use a module in the same context it is defined. Try defining the module outside the context that requires it. 
    (stdlib) lists.erl:1352: :lists.mapfoldl/3 
    (stdlib) lists.erl:1353: :lists.mapfoldl/3 

Trả lời

4

Như thường lệ bạn cần phải đòi hỏi một mô-đun trước khi sử dụng macro của nó để biểu thị đến trình biên dịch thứ tự biên soạn các mô-đun:

defmodule Other do 
    def run do 
    require Sample 

    Sample.doFunc "Hello World via Function" 
    Sample.doIt "Hello World from Macro!" 
    end 
end 

Other.run # => Hello World via Function 
      # Hello World from Macro! 
+0

Ở đây, bạn đã định nghĩa một hàm 'run' trong một mô-đun khác để sử dụng' Sample.doIt' - đây là cách duy nhất để sử dụng macro - gọi nó qua một hàm khác được đặt trong Mô-đun –

+3

. là một hạn chế của trình biên dịch. Khi lỗi nói - bạn không thể sử dụng Macro từ mô-đun trong cùng một ngữ cảnh nơi mô-đun được xác định. Tôi đoán nó đã làm với cách trình biên dịch đơn đặt hàng những thứ để biên dịch. –

+3

Vâng, chính xác. Các macro được mở rộng tại thời gian biên dịch vì vậy khi chúng tôi phân tích cú pháp 'defmodule Foo' theo sau là' Foo.some_macro', chúng tôi vẫn chưa biên dịch 'Foo', vì vậy chúng tôi không biết cách mở rộng macro. –

Các vấn đề liên quan