2011-06-08 7 views
7

अस्वीकरण: कोई इससे पहले कि यह कहता है: हाँ, मुझे पता है कि यह खराब शैली है और प्रोत्साहित नहीं किया गया है। मैं बस स्कैला के साथ खेलने के लिए ऐसा कर रहा हूं और इस बारे में अधिक जानने की कोशिश करता हूं कि प्रकार अनुमान प्रणाली कैसे काम करती है और कैसे नियंत्रण प्रवाह को ट्विक करें। मैं अभ्यास में इस कोड का उपयोग करने का इरादा नहीं रखता हूं।मैं स्कैला में एक विधि के शरीर से बाहर की वापसी कैसे लागू कर सकता हूं?


तो: लगता है कि मैंने शुरू में लगातार जांच करता है के बहुत सारे है, जो, अगर वे असफल हो, सभी कुछ अन्य मान (नहीं फेंक) करने के लिए समारोह का कारण करने वाले हैं के साथ एक नहीं बल्कि लंबा समारोह में हूँ, , और अन्यथा सामान्य मूल्य वापस कर दें। मैं Function के शरीर में return का उपयोग नहीं कर सकता। लेकिन क्या मैं इसे अनुकरण कर सकता हूं? break की तरह थोड़ा scala.util.control.Breaks में अनुकरण किया गया है?

मैं इस के साथ आए हैं: यहाँ स्पष्ट रूप से

object TestMain { 

    case class EarlyReturnThrowable[T](val thrower: EarlyReturn[T], val value: T) extends ControlThrowable 
    class EarlyReturn[T] { 
    def earlyReturn(value: T): Nothing = throw new EarlyReturnThrowable[T](this, value) 
    } 

    def withEarlyReturn[U](work: EarlyReturn[U] => U): U = { 
    val myThrower = new EarlyReturn[U] 
    try work(myThrower) 
    catch { 
     case EarlyReturnThrowable(`myThrower`, value) => value.asInstanceOf[U] 
    } 
    } 

    def main(args: Array[String]) { 
    val g = withEarlyReturn[Int] { block => 
     if (!someCondition) 
     block.earlyReturn(4) 

     val foo = precomputeSomething 
     if (!someOtherCondition(foo)) 
     block.earlyReturn(5) 

     val bar = normalize(foo) 
     if (!checkBar(bar)) 
     block.earlyReturn(6) 

     val baz = bazify(bar) 
     if (!baz.isOK) 
     block.earlyReturn(7) 

     // now the actual, interesting part of the computation happens here 
     // and I would like to keep it non-nested as it is here 
     foo + bar + baz + 42 // just a dummy here, but in practice this is longer 
    } 
    println(g) 
    } 
} 

मेरे चेकों रहे हैं डमी, लेकिन मुख्य मुद्दा यह है कि मैं कुछ इस तरह से बचना चाहते है, जहां वास्तव में दिलचस्प कोड तरह से किया जा रहा समाप्त होता है भी मेरे स्वाद के लिए नेस्ट:

if (!someCondition) 4 else { 
    val foo = precomputeSomething 
    if (!someOtherCondition(foo)) 5 else { 
    val bar = normalize(foo) 
    if (!checkBar(bar)) 6 else { 
     val baz = bazify(bar) 
     if (!baz.isOK) 7 else { 
     // actual computation 
     foo + bar + baz + 42 
     } 
    } 
    } 
} 

मेरे यहाँ समाधान ठीक काम करता है, और मैं 4 के साथ जल्दी लौट सकते हैं वापसी मान के रूप में अगर मैं चाहता हूँ। परेशानी है, मैं को टाइप पैरामीटर [Int] स्पष्ट रूप से लिखने के लिए है - जो दर्द का थोड़ा सा है। क्या मैं इस तरह से कोई रास्ता प्राप्त कर सकता हूं?

+1

मुझे नहीं लगता कि यह _always_ खराब अभ्यास है। ऐसा लगता है कि भाषाओं में अधिक उपयोग किया जाता है जो इसे आसान बनाता है और अच्छे विकल्प प्रदान नहीं करता है। –

+2

यदि आप उथले तरीके से अपना केस भेद लिखते हैं ('else if' का उपयोग करके), तो आपकी" वास्तविक गणना "केवल आपके हैक में घोंसला नहीं होने की तुलना में घोंसला होती है। उसमें क्या समस्या है? आपके उदाहरण में, आप जो भी सहेजते हैं वह एक कीवर्ड 'else' है लेकिन आपके पास सभी ओवरहेड हैं। – Raphael

+0

@ राफेल हां * उस उदाहरण में *, लेकिन मैंने यह निर्दिष्ट किया है कि मैं उन मामलों को देख रहा हूं जहां निश्चित रूप से, मेरे पास जांच करने के लिए एक से अधिक शर्त हैं - आमतौर पर 3 या 4, इसलिए मेरा वास्तविक कोड 3 घोंसला होगा या 4 बार। –

उत्तर

3

यह अपने मुख्य सवाल का एक सा कोई संबंध नहीं है, लेकिन मुझे लगता है, एक अधिक प्रभावी दृष्टिकोण (एक अपवाद फेंकने की आवश्यकता नहीं है कि) को लागू करने के return निरंतरता शामिल होगा: यहां

def earlyReturn[T](ret: T): Any @cpsParam[Any, Any] = shift((k: Any => Any) => ret) 
def withEarlyReturn[T](f: => T @cpsParam[T, T]): T = reset(f) 
def cpsunit: Unit @cps[Any] =() 

def compute(bool: Boolean) = { 
    val g = withEarlyReturn { 
     val a = 1 
     if(bool) earlyReturn(4) else cpsunit  
     val b = 1 
     earlyReturn2(4, bool)    
     val c = 1 
     if(bool) earlyReturn(4) else cpsunit    
     a + b + c + 42 
    } 
    println(g) 
} 

केवल समस्या, यह है कि आपको स्पष्ट रूप से cpsunit का उपयोग करना होगा।

EDIT1: हाँ, earlyReturn(4, cond = !checkOK) लागू किया जा सकता है, लेकिन यह नहीं होगा कि सामान्य और सुरुचिपूर्ण:

def earlyReturn2[T](ret: T, cond: => Boolean): Any @cpsParam[Any, Any] = 
          shift((k: Any => Any) => if(cond) ret else k()) 

स्निपेट में k ऊपर गणना के बाकी प्रतिनिधित्व करता है। cond के मान के आधार पर, हम या तो मान वापस कर देते हैं, या गणना जारी रखते हैं।

EDIT2:Any chance we might get rid of cpsunit? समस्या है कि यहाँ shiftif बयान अंदर else बिना अनुमति नहीं है। संकलक Unit को Unit @cps[Unit] में कनवर्ट करने से इंकार कर देता है।

+0

धन्यवाद, बहुत ही रोचक दृष्टिकोण। क्या आप उन लोगों के लिए कुछ और स्पष्टीकरण जोड़ना चाहते हैं जो निरंतरता से परिचित नहीं हैं? –

+0

कोई मौका हम 'cpsunit' से छुटकारा पा सकते हैं अगर हम' प्रारंभिक वापसी (4, cond =! CheckOK) 'जैसे कॉल की अनुमति देते हैं, तो स्थिति को बुलियन परम में ले जाया जाता है? या क्या आपके मन में कुछ और सुरुचिपूर्ण होगा? अंत में: क्या निरंतरता के साथ दृष्टिकोण अभी भी काम करता है अगर उनमें से कई घोंसले हैं? –

+0

>> "क्या निरंतरता के साथ दृष्टिकोण अभी भी काम करता है अगर उनमें से कई नेस्टेड हैं?" कुछ संपादन के साथ, हाँ, यह करता है। –

0

मुझे लगता है कि एक कस्टम अपवाद यहां सही वृत्ति है।

संबंधित मुद्दे

 संबंधित मुद्दे