2015-06-19 14 views
7

Tại sao công việc này:Julia splatting vĩ mô

function test_func(a, b) 
    a + b 
end 

test_func((1, 2)...) 

Nhưng điều này không?

macro test_func(a, b) 
    a + b 
end 

@test_func((1, 2)...) 

Đây có phải là lỗi trong Julia không?

Trả lời

10

Macro hoạt động trên cú pháp bề mặt, vì vậy @test_func không nhìn thấy kết quả của biểu tượng. Thay vào đó, nó thấy chính hoạt động của splat! Như mọi khi, một cách tuyệt vời để kiểm tra này là để trích dẫn nó và xem chính xác những gì cú pháp vĩ mô đang hoạt động trên:

julia> :(@test_func((1,2)...)) 
:(@test_func (1,2)...) 

julia> Meta.show_sexpr(ans) 
(:macrocall, symbol("@test_func"), (:..., (:tuple, 1, 2))) 

Vì vậy, các vĩ mô chỉ được nhận một đối số (không hai), và nó là một Expr(:..., Expr(:tuple, 1, 2)). Lưu ý rằng tuple (1,2) được chuyển tới macro của bạn, nhưng nó chỉ bị ẩn đi bên trong hoạt động của trình tách. Vì vậy, bạn có thể thâm nhập vào các Expr và loại-of-loại-of thực hiện splatting mình:

julia> macro test_func(as...) 
      if length(as) == 1 && isa(as[1], Expr) && as[1].head == :... && 
        isa(as[1].args[1], Expr) && as[1].args[1].head == :tuple 
       a, b = as[1].args[1].args 
      elseif length(as) == 2 
       a, b = as 
      else 
       error("unsupported syntax $as") 
      end 
      return esc(:($a + $b)) 
     end 

julia> @test_func((1,2)...) 
3 

Nhưng loại-of-loại-of hỗ trợ splatting chỉ này. Hãy xem điều gì sẽ xảy ra nếu bạn cố gắng hoạt động trên một biến thay thế:

julia> @test_func(xs...) 
ERROR: unsupported syntax (:(xs...),) 

Hiện tại không có cách nào để macro biết cần thêm gì cùng nhau!