2013-09-01 41 views
8

Quasiquotes thật tuyệt vời - chúng làm cho các macro viết ở Scala cực kỳ ít đau đớn, và theo kinh nghiệm của tôi, chúng hầu như luôn hoạt động đúng như mong đợi. Và tốt nhất là, họ hiện có sẵn as a plugin trong Scala 2.10.Quasiquotes cho nhiều tham số và danh sách tham số

Câu hỏi này là về một vấn đề nhỏ mà tôi gặp phải khi viết this blog post. Đó là trong danh sách các công cụ của tôi để xem xét khi tôi có thể tìm thấy một vài phút, nhưng tôi figured tôi đăng nó ở đây trong trường hợp một người nào khác có thể đánh bại tôi với nó, và để giúp những người khác đang chạy vào cùng một câu hỏi.

Giả sử tôi có một danh sách liệt kê các cặp tên-type:

val pss = List(
    List(newTermName("x") -> typeOf[Int], newTermName("y") -> typeOf[Char]), 
    List(newTermName("z") -> typeOf[String]) 
) 

Tôi muốn biến chúng thành một cây trông như thế này:

def foo(x: Int, y: Char)(z: String) = ??? 

Các công việc sau tốt:

q"def bar(${pss.head.head._1}: ${pss.head.head._2}) = ???" 

Tức là, nó xây dựng cây sau:

def bar(x: Int) = ??? 

Những gợi ý rằng tôi sẽ có thể viết một cái gì đó như thế này:

val quoted = pss.map(_.map { case (n, t) => q"$n: $t" }) 

q"def foo..${quoted.map(ps => q"($ps)")} = 1" 

Hoặc đơn giản hơn một chút, với nhiều tham số trong một danh sách tham số duy nhất:

q"def baz(..${quoted.head}) = ???" 

Cả công trình —Tôi nhận được lỗi như sau:

<console>:28: error: type mismatch; 
found : List[c.universe.Typed] 
required: List[c.universe.ValDef] 
      q"def baz(..${quoted.head}) = ???" 
           ^

Đủ công bằng — Tôi có thể e nó sẽ trông như thế nào với quasiquoter như tôi đang xây dựng các biểu thức đã gõ hơn là định nghĩa các tham số trong quoted. Không có điều rõ ràng nào tôi có thể nghĩ để thử làm việc (thêm = _, nhập rõ ràng quasiquote là ValDef, v.v.).

tôi biết rằng tôi có thể xây dựng các định nghĩa tham số bằng tay:

val valDefs = pss.map(
    _.map { 
    case (n, t) => ValDef(Modifiers(Flag.PARAM), n, TypeTree(t), EmptyTree) 
    } 
) 

Và bây giờ là baz phiên bản (với một danh sách tham số) hoạt động:

q"def baz(..${valDefs.head}) = ???" 

Nhưng không phải phiên bản foo (một trong những với nhiều danh sách tham số).

Vì vậy, có hai câu hỏi ở đây. Trước tiên, làm thế nào tôi có thể sử dụng quasiquotes để biến một cặp tên kiểu thành một tham số ValDef bên ngoài ngữ cảnh của một danh sách tham số được trích dẫn? Và thứ hai, làm thế nào tôi có thể chuyển danh sách các danh sách các định nghĩa tham số thành nhiều danh sách tham số? Dễ dàng đủ để quay trở lại xây dựng AST thủ công cho toàn bộ điều damn (xem my post cho một ví dụ), nhưng tôi muốn có thể sử dụng quasiquotes thay vào đó.

+2

1) Tôi tin rằng q "val $ n: $ t" sẽ làm việc 2) Sử dụng ... $ để ghép danh sách liệt kê –

+0

'val' hoạt động hoàn hảo ở đây — cảm ơn! '... $ quoted' không, mặc dù - tôi đoán vì các danh sách bên trong không tự động được nâng lên các danh sách tham số? –

Trả lời

4

Dưới đây là giải pháp nhanh chóng cho vấn đề của bạn:

val pss = List(
    List(newTermName("x") -> typeOf[Int], newTermName("y") -> typeOf[Char]), 
    List(newTermName("z") -> typeOf[String]) 
) 
val vparamss: List[List[ValDef]] = pss.map { _.map { case (name, tpe) => q"val $name: $tpe" } } 
q"def foo(...$vparamss)" 

Như bạn thấy đặc biệt ... $ nối cho phép bạn xác định một chức năng với nhiều danh sách đối số. Các đối số chức năng được thể hiện theo cách tương tự như các vals thông thường.

Một ví dụ khác nơi ... $ nó có thể có ích:

val xy = List(List(q"x"), List(q"y")) 
q"f(...$xy)" // same as q"f(x)(y)" 
+0

Hoạt động hoàn hảo, cảm ơn! Tôi không nghĩ rằng để thử đưa danh sách các danh sách tham số vào dấu ngoặc đơn, nhưng tôi có thể thấy rằng nó có ý nghĩa khi sử dụng nó làm cú pháp ở đây. –

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