2012-03-21 9 views
35

पार्सर संयोजक लाइब्रेरी से Parsers.scala (स्कैला 2.9.1) फ़ाइल में मुझे लगता है कि "आलसी तर्क" नामक एक कम ज्ञात स्कैला सुविधा में आया है। वहाँ कुछ आलसी वैल p करने के लिए कॉल-दर-नाम तर्क q के काम के साथ यहां चल रहा हैस्कैला के आलसी तर्क: वे कैसे काम करते हैं?

def ~ [U](q: => Parser[U]): Parser[~[T, U]] = { lazy val p = q // lazy argument 
    (for(a <- this; b <- p) yield new ~(a,b)).named("~") 
} 

जाहिर है,: यहाँ एक उदाहरण है।

अभी तक मैं यह नहीं कर पाया कि यह क्या करता है और यह क्यों उपयोगी है। क्या कोई मदद कर सकता है?

+1

आप अपने आप को यह पता लगाने की कोशिश कर रहा में किसी भी प्रयास किया है? यह स्कैला भाषा का हिस्सा है और एक इंटरनेट खोज को 'स्कैला आलसी' पर पर्याप्त हिट प्रकट करनी चाहिए। – ziggystar

+1

@ziggystar: मैंने पहले से ही 2-3 Google खोज की हैं और कुछ भी उपयोगी नहीं मिल सका। कुछ स्काला फीचर अनुरोध पर आलसी तर्कों का उल्लेख किया गया था, लेकिन कोई स्पष्टीकरण नहीं जिसे मैं समझ सकता था वहां दिया गया था। –

+1

@ziggystar: सुविधा अनुरोध यहां है: https://issues.scala-lang.org/browse/SI-240। इसके अलावा, 'स्कैला आलसी' या यहां तक ​​कि 'स्कैला आलसी तर्क' की तलाश में बहुत उपयोगी जानकारी नहीं मिलती है क्योंकि आपको ज्यादातर आलसी वैल और कॉल-बाय-नाम जैसी अधिक बुनियादी सामग्री के बारे में परिणाम मिलेंगे। –

उत्तर

76

कॉल-बाय-नाम तर्कों को कहा जाता है जब भी आप उन्हें पूछते हैं। आलसी vals को पहली बार कहा जाता है और फिर मान संग्रहीत किया जाता है। यदि आप इसे फिर से पूछते हैं, तो आपको संग्रहीत मूल्य मिल जाएगा।

इस प्रकार, जैसे

def foo(x: => Expensive) = { 
    lazy val cache = x 
    /* do lots of stuff with cache */ 
} 

एक पैटर्न अंतिम पुट-ऑफ काम के रूप में लंबे समय के रूप में संभव है और केवल करते हैं यह एक बार पैटर्न है। यदि आपका कोड पथ आपको x पर कभी भी आवश्यकता नहीं लेता है, तो इसका मूल्यांकन कभी नहीं किया जाएगा। यदि आपको इसे कई बार चाहिए, तो इसका मूल्यांकन केवल एक बार किया जाएगा और भविष्य के उपयोग के लिए संग्रहीत किया जाएगा। तो आप महंगे कॉल को शून्य (यदि संभव हो) या एक (यदि नहीं) बार, गारंटी देते हैं।

+1

+1, मैंने माना था कि कॉल-बाय-नाम कुछ आलसी के बराबर था, लेकिन सभी मामलों में नहीं! स्पष्टीकरण के लिए धन्यवाद ... – virtualeyes

+0

उर्फ ​​कॉल ज़रूरत है – JPC

20

Scala के लिए विकिपीडिया लेख भी जवाब देता है क्या lazy कीवर्ड करता है:

कीवर्ड आलसी का उपयोग करते हुए जब तक यह मान प्रयोग किया जाता है एक मूल्य के प्रारंभ defers।

इसके अतिरिक्त, q : => Parser[U] के साथ इस कोड नमूने में आपके पास क्या है, कॉल-बाय-नाम पैरामीटर है। एक पैरामीटर घोषित किया गया है जब तक कि आप अपनी विधि में इसे कहीं भी स्पष्ट रूप से मूल्यांकन नहीं करते हैं, तब तक यह मूल्यांकन नहीं किया जाता है।

scala> def f(p: => Int, eval : Boolean) = if (eval) println(p) 
f: (p: => Int, eval: Boolean)Unit 

scala> f(3, true) 
3 

scala> f(3/0, false) 

scala> f(3/0, true) 
java.lang.ArithmeticException:/by zero 
    at $anonfun$1.apply$mcI$sp(<console>:9) 
    ... 

आप देख सकते हैं, 3/0 दूसरी कॉल में सभी पर मूल्यांकन किया जाता नहीं प्राप्त करता है:

यहाँ कैसे कॉल-दर-नाम मापदंडों काम पर स्केला आरईपीएल से एक उदाहरण है। निम्न अर्थों में ऊपर दिए गए परिणामों जैसे कॉल-बाय-नाम पैरामीटर के साथ आलसी मान का संयोजन: पैरामीटर q विधि को कॉल करते समय तुरंत मूल्यांकन नहीं किया जाता है। इसके बजाय इसे आलसी मूल्य p को सौंपा गया है, जिसका तुरंत मूल्यांकन नहीं किया जाता है। केवल बाद में, जब p का उपयोग किया जाता है तो यह q के मूल्यांकन की ओर जाता है। लेकिन, pval पैरामीटर q का मूल्यांकन केवल का मूल्यांकन पर किया जाएगा और परिणाम बाद में लूप में पुन: उपयोग के लिए p में संग्रहीत किया जाएगा।

आप आसानी से repl में देख सकते हैं, जो एक से अधिक मूल्यांकन अन्यथा हो सकता है:

scala> def g(p: => Int) = println(p + p) 
g: (p: => Int)Unit 

scala> def calc = { println("evaluating") ; 10 } 
calc: Int 

scala> g(calc) 
evaluating 
evaluating 
20 
संबंधित मुद्दे