2012-04-13 17 views
8

में अभिव्यक्तियों की एक श्रृंखला से एक सूची तैयार करें जब मैं स्कैला में आंतरिक डीएसएल बनाने की कोशिश करता हूं, तो मैं एक आम समस्या में भाग लेता हूं और मैं समाधान तैयार करने में सक्षम नहीं हूं। चीजें अधिक एक ठेठ भाषा जैसे दिखते हैं बनाने के लिए, मैं वाक्य रचना कुछ इस तरह देखने के लिए करना चाहते हैं:स्कैला

model 'Foo { 
    decl 'Real 'x; 
    decl 'Real 'y; 
} 

अभ्यास में, वहाँ कई मुद्दे हैं। इस तरह से दो तर्क लेने के लिए पहली समस्या model ऑब्जेक्ट प्राप्त कर रही है। अगर किसी के पास कोई विचार है, तो मुझे बताएं।

model('Foo) { 
    ... 
} 

कहाँ मॉडल अब एक समारोह जो तब एक apply विधि जो तब लैम्ब्डा कि इस प्रकार की खपत के साथ एक वस्तु देता है: लेकिन क्या मैं बजाय किया है कुछ इस तरह थोड़ा और करना है। मैं साथ रह सकता हूँ मैं लैम्ब्डा के अंदर भी इसी तरह के मुद्दे के साथ रह सकता था, इसलिए अंदर decl 'Real 'x या decl('Real,'x) जैसी चीज़ें। लेकिन मैं जो करना चाहता हूं वह है कि सूची के रूप में "लौटा" पाने के लिए स्क्विगली ब्रेसिज़ के अंदर उन सभी अभिव्यक्तियों के परिणाम प्राप्त करना। दूसरे शब्दों में, क्या मैं चाहता हूँ कुछ इस तरह लिखने के लिए:

model 'Foo { 
    decl('Real,'x); 
    decl('Real,'y); 
} 

जहां decl(...) प्रकार Declaration के बारे में कुछ करने के लिए मूल्यांकन करता है और {...} तो List[Declaration] मूल्यांकन करता है। मुझे संदेह है कि ऐसा करने के लिए implicits का उपयोग करने का कोई तरीका है, लेकिन मैं इसे खोजने में सक्षम नहीं हूं। संक्षेप में, मैं करना चाहते हैं:

model 'Foo { 
    decl('Real,'x); 
    decl('Real,'y); 
} 

... के बराबर का मूल्यांकन ...

model 'Foo { 
    decl('Real,'x) :: 
    decl('Real,'y) :: 
    Nil 
} 

टिप्पणियां या सुझाव?

उत्तर

4

पहली बार एक विचार के रूप में, आप चर तर्क सूचियों की कोशिश कर सकते हैं, जो आप के बजाय अल्पविराम के अर्द्ध कोलन का उपयोग करने की अनुमति देता है:

case class Declaration(name: String) 

def decl(s: String) = Declaration(s) 

case class Model(sym: Symbol, decls: List[Declaration]) 

def model(sym: Symbol)(decls: Declaration*) = 
    Model(sym, decls.toList) 

val m = model('Foo)(
    decl("bar"), 
    decl("baz") 
) 

वैकल्पिक रूप से, आप एक trait का विस्तार कर सकता है कुछ कोष्ठकों के और से छुटकारा पाने के अल्पविराम का:

case class ModelBuilder(sym: Symbol) { 
    def using(decls: Declarations) = Model(sym, decls.toList) 
} 

trait Declarations { 

    protected var decls = List[Declaration]() 

    protected def decl(s: String) = 
decls ::= Declaration(s) 

    def toList = decls 
} 

def model(sym: Symbol) = ModelBuilder(sym) 

model('Foo) using new Declarations { 
    decl("bar") 
    decl("baz") 
} 
+0

हां, मैंने कुछ घोषणात्मक जीयूआई डीएसएल के साथ भी इस दृष्टिकोण को देखा है। मैं मानता हूं कि यह करीब है। मैं बस पूरी चीज के आसपास() का उपयोग करने की आवश्यकता नहीं थी और "," उपयोग करने की आवश्यकता समस्याग्रस्त है क्योंकि हर बार जब आप जोड़ना या हटाना चाहते हैं, तो आपको चीजों के बीच "," होने की चिंता करने की ज़रूरत है, लेकिन नहीं अतं मै। –

+0

मैंने आपकी टिप्पणी का उत्तर देने के लिए मेरा उत्तर संशोधित किया। – paradigmatic

+0

आह, बहुत चालाक। कन्स्ट्रक्टर सिंटैक्स और स्थानीय रूप से परिभाषित तरीकों का उपयोग करना। मुझे यह पसंद है और मुझे लगता है कि यह काम कर सकता है। असल में, मैं इसे "नया मॉडल ('Foo) {...}" तक सरल बना सकता हूं जो कोड को नीचे लाता है। इस तथ्य का फायदा उठाने का अच्छा तरीका है कि एक कन्स्ट्रक्टर संदर्भ में squiggly ब्रेसिज़ आपको उस दायरे में आसानी से चीजों को पेश करने की अनुमति देता है। मुझे आश्चर्य है कि स्कैला 2.10 मैक्रोज़ इसे और भी आसान बना देगा? –

2

ठीक है, पूरी तरह से एहसास है कि 'Foo मॉडल का नाम माना जाता है के बाद इस संशोधित किया गया।

trait DSL { 

    private var currentModel: ModelBuilder = null 
    case class Declaration(kind: Symbol, name: Symbol) 
    case class Model(name: Symbol, declarations: List[Declaration]) 
    case class ModelBuilder(name: Symbol, var declarations: Vector[Declaration]) { 
    def -(f: => Unit) = { 
     currentModel = this 
     f 
     Model(name, declarations.toList) 
    } 
    } 

    def decl (s1: Symbol, s2: Symbol) { 
    currentModel.declarations :+= Declaration(s1, s2) 
    } 

    object model { 
    def - (s: Symbol) = ModelBuilder(s, Vector.empty) 
    } 
} 
उपयोग-स्थल पर

तब:

object UseSite extends App with DSL { 

    val m = 

    model - 'Foo - { 
     decl ('Real, 'x) 
     decl ('Real, 'y) 
    } 

    println(m) 
    //Model('Foo,List(Declaration('Real,'x), Declaration('Real,'y))) 
} 

तो चालबाज़ियों यहाँ

1) एक चर का उपयोग कर मौजूदा मॉडल

2) - प्रतीकों का उपयोग पर नज़र रखने के लिए कर रहे हैं विधि नामों के लिए (यदि आप कोष्ठक पसंद करते हैं तो आप apply का उपयोग कर सकते हैं)

3) एक बिल्डर थोड़ा ज्यादा का उपयोग कर ताकि लौटे वर्ग अपरिवर्तनीय हो सकता है बस कुछ अल्पविराम का ... :)

4

हे भगवान क्या मैंने किया है से बचने के लिए हालांकि

, TBH इस हो सकता है?

import scala.collection.mutable.ListBuffer 

case class Declaration(t: Symbol, name: Symbol) 
case class Model(name: Symbol, declarations: List[Declaration]) 

object model extends Dynamic { 
    val buffer = ListBuffer.empty[Model] 

    def applyDynamic(name: String)(args: Any*) { 
    buffer += Model(Symbol(name), decl.buffer.toList) 
    decl.buffer.clear() 
    } 
} 

object decl extends Dynamic { 
    val buffer = ListBuffer.empty[Declaration] 

    def applyDynamic(t: String)(args: Any*) { 
    args match { 
     case Seq(name: Symbol) => buffer += Declaration(Symbol(t), name) 
    } 
    } 
} 

model Foo { 
    decl Real 'x 
    decl Real 'y 
} 

assert(model.buffer.head == Model('Foo, List(
    Declaration('Real, 'x), Declaration('Real, 'y)))) 
+0

एक महान जवाब पर बधाई! मुझे लगता है कि यह सिर्फ 'गतिशील' के लिए है। –