2012-12-01 26 views
9

मान लीजिए मैं इस मैक्रो हैस्काला मैक्रो में varargs प्रकार जोड़ना के लिए जांच की जा रही

scala> FooExample.foo(List(1, 2, 3): _*) 
res1: Int = 1 

और पता चलता है कि गड़बड़ कुछ भी नहीं वाई चल रहा है: varargs प्रकार मेरे लिए (स्काला 2.10.0-RC3 में) भ्रामक है अनुमानित प्रकार:

scala> FooExample.foo[Int](List(1, 2, 3): _*) 
res2: Int = 1 

मुझे यहां एक संकलन-समय त्रुटि की उम्मीद होगी, और यही वही है जो मैं चाहता हूं।

object BarExample { 
    def bar(xs: Int*): Int = macro bar_impl 
    def bar_impl(c: Context)(xs: c.Expr[Int]*) = { 
    import c.universe._ 
    c.literal(
     xs.map(_.tree).headOption map { 
     case Literal(Constant(x: Int)) => x 
     case _ => c.abort(c.enclosingPosition, "bar wants literal arguments!") 
     } getOrElse c.abort(c.enclosingPosition, "bar wants arguments!") 
    ) 
    } 
} 

और यह संकलन समय पर समस्या पकड़ता:

scala> BarExample.bar(3, 2, 1) 
res3: Int = 3 

scala> BarExample.bar(List(3, 2, 1): _*) 
<console>:8: error: bar wants literal arguments! 
       BarExample.bar(List(3, 2, 1): _*) 

यह मेरे लिए, यद्यपि एक हैक की तरह लगता है मैं मैक्रो मैं लिखा है के अधिकांश में निम्नलिखित दृष्टिकोण का उपयोग किया है यह एक बिट प्रमाणीकरण (यह जांच कर रहा है कि तर्क अक्षर हैं) एक दूसरे के साथ मिश्रण (यह पुष्टि करना कि हमारे पास वास्तव में varargs हैं)। मैं ऐसे मामलों की भी कल्पना कर सकता हूं जहां मुझे शाब्दिक होने के तर्कों की आवश्यकता नहीं है (या जहां मैं उनका प्रकार सामान्य होना चाहता हूं)।

मैं जानता हूँ कि मैं निम्नलिखित कर सकता है:

object BazExample { 
    def baz[A](xs: A*): Int = macro baz_impl[A] 
    def baz_impl[A](c: Context)(xs: c.Expr[A]*) = { 
    import c.universe._ 

    xs.toList.map(_.tree) match { 
     case Typed(_, Ident(tpnme.WILDCARD_STAR)) :: Nil => 
     c.abort(c.enclosingPosition, "baz wants real varargs!") 
     case _ => c.literal(xs.size) 
    } 
    } 
} 

लेकिन यह एक बहुत ही सरल (और मैं व्यापक रूप से आवश्यक लगता था) तर्क सत्यापन के बिट से निपटने में एक बदसूरत तरीका है। क्या कोई चाल है जो मुझे याद आ रही है? सबसे आसान तरीका यह है कि मैं यह सुनिश्चित कर सकता हूं कि foo(1 :: Nil: _*) मेरे पहले उदाहरण में संकलन-समय त्रुटि देता है?

+0

जब आप लिखते हैं "मुझे यहां संकलन-समय त्रुटि की उम्मीद होगी", तो क्या आप कृपया स्पष्टीकरण दे सकते हैं? आप यह एक त्रुटि होने की उम्मीद करेंगे, क्योंकि यह आपके डोमेन की आवश्यकता है? या यह vararg मैक्रोज़ के सभी प्रकार के लिए एक त्रुटि होनी चाहिए? –

+0

@EugeneBurmako: मेरी चिंता यह है कि लिखित मामले में, 'xs.head' वास्तव में' c.Expr [ए] 'नहीं है-यह' c.Expr [Seq [A]] 'की तरह है। यहां [कुछ उदाहरण हैं] (https://gist.github.com/4191360)। –

उत्तर

1

क्या यह अपेक्षित काम करता है?

object BarExample { 
    def bar(xs: Int*): Int = macro bar_impl 
    def bar_impl(c: Context)(xs: c.Expr[Int]*) = { 
    import c.universe._ 
    import scala.collection.immutable.Stack 
    Stack[Tree](xs map (_.tree): _*) match { 
     case Stack(Literal(Constant(x: Int)), _*) => c.literal(x) 
     case _ => c.abort(c.enclosingPosition, "bar wants integer constant arguments!") 
    } 
    } 
} 
+0

धन्यवाद, लेकिन यह अनिवार्य रूप से मेरे 'BarExample' जैसा ही है, और सामान्य मामले में काम नहीं करेगा। –