2012-07-09 11 views
41

मैं थोड़ी देर के लिए स्कैला के साथ काम कर रहा हूं और इसके साथ 10,000+ लाइन प्रोग्राम लिखा है, लेकिन मैं अभी भी कुछ आंतरिक कार्यकलापों से उलझन में हूं। मैं जावा, सी और लिस्प के साथ पहले से ही घनिष्ठ परिचित होने के बाद पाइथन से स्कैला आया था, लेकिन फिर भी यह धीमा हो रहा है, और एक बड़ी समस्या यह है कि मुझे अक्सर निराशाजनक कठिनाई होती है जब वस्तुओं/प्रकारों के आंतरिक कार्यों की जांच करने की कोशिश की जाती है/वर्गों/आदि। पाइथन की तुलना में स्कैला आरईपीएल का उपयोग करना। पाइथन में आप foo (प्रकार, ऑब्जेक्ट वैरिएबल, बिल्ट-इन फ़ंक्शन इत्यादि) का उपयोग करके foo का उपयोग करके यह देखने के लिए type(foo) का उपयोग करने के लिए किसी भी ऑब्जेक्ट की जांच कर सकते हैं, dir(foo) आपको उन तरीकों को बताने के लिए जिन्हें आप कॉल कर सकते हैं अंतर्निहित दस्तावेज़ प्राप्त करने के लिए, और help(foo) पर। re नामक पैकेज पर प्रलेखन का पता लगाने के लिए आप help("re") जैसी चीजें भी कर सकते हैं (जो नियमित रूप से अभिव्यक्ति ऑब्जेक्ट्स और विधियों को रखता है), भले ही इसके साथ कोई ऑब्जेक्ट न हो।ऑब्जेक्ट्स/प्रकार/आदि की जांच कैसे करें। स्कैला आरईपीएल से?

स्कैला में, आप ऑनलाइन दस्तावेज़ीकरण को आजमा सकते हैं और पढ़ सकते हैं, लाइब्रेरी में स्रोत कोड देख सकते हैं, लेकिन यह अक्सर उन चीजों के लिए बहुत कठिन हो सकता है जहां आप नहीं जानते कि वे कहां हैं या यहां तक ​​कि वे क्या हैं (और यह अक्सर बड़े पैमाने पर पदानुक्रम को देखते हुए काटने के लिए एक बड़ा हिस्सा होता है) - सामान विभिन्न स्थानों (पैकेज scala, Predef, विभिन्न निहित रूपांतरणों, :: जैसे प्रतीकों के आसपास तैर रहा है जो Google के लिए लगभग असंभव हैं)। आरईपीएल सीधे पता लगाने का तरीका होना चाहिए, लेकिन हकीकत में, चीजें कहीं अधिक रहस्यमय हैं। कहें कि मैंने कहीं foo का संदर्भ देखा है, लेकिन मुझे नहीं पता कि यह क्या है। वहाँ जाहिरा तौर पर "व्यवस्थित आरईपीएल साथ स्काला थिंगी की जांच करने के लिए गाइड" एक जैसी कोई बात नहीं है, लेकिन अगले क्या मैं परीक्षण और त्रुटि के एक महान सौदा के बाद में इकट्ठा किया है:

  1. तो foo एक मूल्य के (है जो संभवतः चर और प्लस साथी वस्तुओं और अन्य स्कैला object एस में संग्रहीत चीजों को शामिल करता है), आप सीधे foo का मूल्यांकन कर सकते हैं। यह आपको परिणाम के प्रकार और मूल्य बताना चाहिए। कभी-कभी परिणाम सहायक होता है, कभी-कभी नहीं।
  2. यदि foo एक मान है, तो आप इसका प्रकार प्राप्त करने के लिए :type foo का उपयोग कर सकते हैं। (जरूरी नहीं है।) यदि आप फ़ंक्शन कॉल पर इसका उपयोग करते हैं, तो आपको फ़ंक्शन कॉल किए बिना वापसी मान का प्रकार मिलता है।
  3. यदि foo एक मूल्य है, तो आप अपनी कक्षा प्राप्त करने के लिए foo.getClass का उपयोग कर सकते हैं। (अक्सर पिछले की तुलना में अधिक प्रबुद्ध, लेकिन ऑब्जेक्ट की कक्षा इसके प्रकार से भिन्न कैसे होती है?)
  4. कक्षा foo के लिए, आप classOf[foo] का उपयोग कर सकते हैं, हालांकि यह स्पष्ट नहीं है कि परिणाम का क्या अर्थ है।
  5. सैद्धांतिक रूप से, आप कक्षा को अलग करने के लिए :javap foo का उपयोग कर सकते हैं - जो सभी का सबसे उपयोगी होना चाहिए, लेकिन मेरे लिए पूरी तरह से और समान रूप से विफल रहता है।
  6. कभी-कभी आपको त्रुटि संदेशों से चीजों को एक साथ टुकड़ा करना होता है। :javap का उपयोग कर विफलता के

उदाहरण:

scala> :javap List 
Failed: Could not find class bytes for 'List' 

शिक्षाप्रद त्रुटि संदेश का उदाहरण:

scala> assert 
<console>:8: error: ambiguous reference to overloaded definition, 
both method assert in object Predef of type (assertion: Boolean, message: => Any)Unit 
and method assert in object Predef of type (assertion: Boolean)Unit 
match expected type ? 
       assert 
      ^

ठीक है, अब के एक सरल उदाहरण कोशिश करते हैं।

scala> 5 
res63: Int = 5 

scala> :type 5 
Int 

scala> 5.getClass 
res64: java.lang.Class[Int] = int 

सरल पर्याप्त ...

अब, चलो कुछ वास्तविक मामलों में, जहां यह तो स्पष्ट नहीं है की कोशिश करते हैं:

scala> Predef 
res65: type = [email protected] 

scala> :type Predef 
type 

scala> Predef.getClass 
res66: java.lang.Class[_ <: object Predef] = class scala.Predef$ 

इसका क्या मतलब है? Predef का प्रकार type का प्रकार क्यों है, जबकि कक्षा scala.Predef$ है? मैं इकट्ठा करता हूं कि $ वह तरीका है कि साथी वस्तुओं को जावा में shoehorned हैं ... लेकिन Google पर स्कैला दस्तावेज़ मुझे बताओ कि Predefobject Predef extends LowPriorityImplicits है - मैं इसे आरईपीएल से कैसे घटा सकता हूं? और मैं इसमें क्या देख सकता हूं? यह मेरे बुरी उलझन में छोड़ दिया

scala> `::` 
res77: collection.immutable.::.type = :: 

scala> :type `::` 
collection.immutable.::.type 

scala> `::`.getClass 
res79: java.lang.Class[_ <: object scala.collection.immutable.::] = class scala.collection.immutable.$colon$colon$ 

scala> classOf[`::`] 
<console>:8: error: type :: takes type parameters 
       classOf[`::`] 
        ^

scala> classOf[`::`[Int]] 
res81: java.lang.Class[::[Int]] = class scala.collection.immutable.$colon$colon 

ठीक है, है, और अंततः मैं यह सब की समझ बनाने के लिए स्रोत कोड को पढ़ने के लिए जाना था:

ठीक है, चलो एक और दुविधापूर्ण कोशिश करते हैं।

तो, मेरे सवाल कर रहे हैं:

  1. क्या आरईपीएल कक्षाएं, विधियों, आदि का उपयोग कर समझ बनाने के लिए की स्काला वस्तुओं, का सच स्काला विशेषज्ञों से सबसे अच्छा तरीका है की सिफारिश की है, या कम से कम उन्हें के रूप में की जांच आरईपीएल से सबसे अच्छा किया जा सकता है?
  2. मैं निर्मित उत्पादों के लिए REPL से काम कर रहे :javap कैसे प्राप्त करूं? (क्या यह डिफ़ॉल्ट रूप से काम नहीं करना चाहिए?)

किसी भी ज्ञान के लिए धन्यवाद।

उत्तर

32

आपने एक महत्वपूर्ण बिंदु का उल्लेख किया जिसमें स्कैला की कमी थी: दस्तावेज़ीकरण।

REPL एक शानदार उपकरण है, लेकिन यह उतना शानदार नहीं है जितना हो सकता है। बहुत अधिक गायब फीचर्स और फीचर्स हैं जिन्हें बेहतर किया जा सकता है - उनमें से कुछ का उल्लेख आपकी पोस्ट में किया गया है। Scaladoc भी एक अच्छा उपकरण है, लेकिन यह सही होने के लिए बहुत दूर है। इसके अलावा एपीआई में बहुत सारे कोड अभी तक बहुत कम दस्तावेज नहीं हैं और कोड उदाहरण अक्सर गायब होते हैं। आईडीई पूर्ण ओबी कीड़े हैं और संभावनाओं की तुलना में जावा आईडीई हमें दिखाते हैं कि वे कुछ किंडरगार्टन खिलौने की तरह दिखते हैं।

फिर भी 2-3 साल पहले स्कैला सीखने के लिए उपलब्ध टूल के मुकाबले स्कालस वर्तमान उपकरण का एक बड़ा अंतर है। उस समय आईडीई ने पृष्ठभूमि में स्थायी रूप से कुछ कचरा संकलित किया, संकलक हर कुछ मिनटों में दुर्घटनाग्रस्त हो गया और कुछ दस्तावेज बिल्कुल असहनीय थे। अक्सर मुझे क्रोध के हमले हुए और स्काला लेखकों को मौत और भ्रष्टाचार की कामना की।

और अब? मेरे पास अब भी इन क्रोध हमलों में से कोई भी नहीं है।क्योंकि वर्तमान में हमारे पास मौजूद उपकरण बहुत अच्छे हैं, हालांकि ये सही नहीं हैं!

docs.scala-lang.org है, जो बहुत सारे महान दस्तावेज़ीकरण को सारांशित करता है। ट्यूटोरियल, धोखा-चादरें, शब्दावली, गाइड और बहुत अधिक अच्छी चीजें हैं। एक और महान उपकरण Scalex है, जो कि अजीब ऑपरेटर भी ढूंढ सकता है जिसे कोई भी सोच सकता है। यह Scalas Hoogle है और भले ही यह अपने महान आदर्श के रूप में उतना अच्छा नहीं है, यह बहुत उपयोगी है।

महान सुधार Scalas खुद प्रतिबिंब पुस्तकालय के रूप में Scala2.10 साथ आ रहे हैं: नई परावर्तन पुस्तकालय के लिए

// needs Scala2.10M4 
scala> import scala.reflect.runtime.{universe => u} 
import scala.reflect.runtime.{universe=>u} 

scala> val t = u.typeOf[List[_]] 
t: reflect.runtime.universe.Type = List[Any] 

scala> t.declarations 
res10: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(constructor List, method companion, method isEmpty, method head, method tail, method ::, method :::, method reverse_:::, method mapConserve, method ++, method +:, method toList, method take, method drop, method slice, method takeRight, method splitAt, method takeWhile, method dropWhile, method span, method reverse, method stringPrefix, method toStream, method removeDuplicates) 

प्रलेखन अभी भी याद आ रही है, लेकिन प्रगति में।

scala> u reify { List(1,2,3) map (_+1) } 
res14: reflect.runtime.universe.Expr[List[Int]] = Expr[List[Int]](immutable.this.List.apply(1, 2, 3).map(((x$1) => x$1.$plus(1)))(immutable.this.List.canBuildFrom)) 

scala> import scala.tools.reflect.ToolBox 
import scala.tools.reflect.ToolBox 

scala> import scala.reflect.runtime.{currentMirror => m} 
import scala.reflect.runtime.{currentMirror=>m} 

scala> val tb = m.mkToolBox() 
tb: scala.tools.reflect.ToolBox[reflect.runtime.universe.type] = [email protected] 

scala> tb.parseExpr("List(1,2,3) map (_+1)") 
res16: tb.u.Tree = List(1, 2, 3).map(((x$1) => x$1.$plus(1))) 

scala> tb.runExpr(res16) 
res18: Any = List(2, 3, 4) 

यह और भी अधिक जब हम जानना चाहते हैं कि स्काला कोड आंतरिक रूप से अनुवाद किया है चाहता हूँ: यह एक आरईपीएल के अंदर एक आसान तरीका में scalac उपयोग करने के लिए अनुमति देता है। पूर्व में वेन को आंतरिक रूप से प्रतिनिधित्व प्राप्त करने के लिए scala -Xprint:typer -e "List(1,2,3) map (_+1)" टाइप करने की आवश्यकता है। इसके अलावा कुछ छोटे सुधार, नई रिलीज करने के लिए वहाँ रास्ता मिल उदाहरण के लिए:

scala> :type Predef 
scala.Predef.type 

Scaladoc कुछ type-hierarchy graph लाभ होगा (पर टाइप पदानुक्रम क्लिक करें)।

मैक्रोज़ के साथ यह अब संभव है, त्रुटि संदेशों को एक शानदार तरीके से सुधारने के लिए।

// copied from GitHub page 
import org.expecty.Expecty 

case class Person(name: String = "Fred", age: Int = 42) { 
    def say(words: String*) = words.mkString(" ") 
} 

val person = Person() 
val expect = new Expecty() 

// Passing expectations 

expect { 
    person.name == "Fred" 
    person.age * 2 == 84 
    person.say("Hi", "from", "Expecty!") == "Hi from Expecty!" 
} 

// Failing expectation 

val word1 = "ping" 
val word2 = "pong" 

expect { 
    person.say(word1, word2) == "pong pong" 
} 

/* 
Output: 

java.lang.AssertionError: 

person.say(word1, word2) == "pong pong" 
|  | |  |  | 
|  | ping pong false 
|  ping pong 
Person(Fred,42) 
*/ 

वहाँ एक उपकरण जो एक GitHub पर होस्ट पुस्तकालयों को खोजने के लिए अनुमति देता है, ls.implicit.ly कहा जाता है: वहाँ एक पुस्तकालय expecty कहा जाता है, जो इस करता है।

आईडीई के पास अब कुछ अर्थपूर्ण हाइलाइटिंग है, यह दिखाने के लिए कि कोई सदस्य ऑब्जेक्ट/टाइप/विधि/जो भी हो। ScalaIDE की अर्थपूर्ण हाइलाइटिंग सुविधा।

आरईपीएल की जावप सुविधा देशी जावप को केवल एक कॉल है, इसलिए यह एक बहुत ही featue समृद्ध उपकरण नहीं है।

scala> :javap scala.collection.immutable.List 
Compiled from "List.scala" 
public abstract class scala.collection.immutable.List extends scala.collection.AbstractSeq implements scala.collection.immutable.LinearSeq,scala.Product,scala.collection.LinearSeqOptimized{ 
... 

कुछ समय पहले मैं एक summary of how Scala code is compiled to Bytecode, जो बातें जानने के लिए का एक बहुत प्रदान करता है लिखा है: आप पूरी तरह से एक मॉड्यूल के नाम अर्हता प्राप्त करने के लिए है।

और सबसे अच्छा: यह सब पिछले कुछ महीनों में किया गया है!

तो, आरईपीएल के अंदर इन सभी चीजों का उपयोग कैसे करें? खैर, यह संभव नहीं है ... अभी तक नहीं। ;)

लेकिन मैं आपको बता सकता हूं कि एक दिन हमारे पास ऐसा आरईपीएल होगा। एक आरईपीएल जो हमें दस्तावेज दिखाता है अगर हम इसे देखना चाहते हैं। एक आरईपीएल जो हमें इसके साथ संवाद करने देता है (शायद lambdabot की तरह)। एक आरईपीएल जो हमें ठंडी चीजें करने देता है, हम अभी भी कल्पना नहीं कर सकते हैं। मुझे नहीं पता कि यह कब होगा, लेकिन मुझे पता है कि पिछले वर्षों में बहुत सी चीजें की गई थीं और मुझे पता है कि अगले वर्षों में भी ज्यादा चीजें की जाएंगी।

+0

एक भयानक लेख के लिए धन्यवाद! मैं 'शोआरओ' का भी उल्लेख करता हूं जिसे एम 4 जारी करने के कुछ ही समय बाद जोड़ा गया था (और कल एम 5 में दिखाई देगा)। यह किसी को कुछ प्रतिबिंब कलाकृतियों (पेड़ों और प्रकारों सहित) की आंतरिक संरचना का निरीक्षण करने देता है। –

+0

@EugeneBurmako: मुझे 'ब्रह्मांड.शोराव' पता है जो एम 4 का सदस्य है, क्या आपका मतलब दूसरा 'शोआर' है? – sschaef

+0

हाँ, मैं इस बारे में बात कर रहा हूं। एम 4 के रिलीज के कुछ दिनों बाद इसे काफी हद तक फिर से बनाया गया था। –

2

आपको पूरी तरह से योग्य कक्षा का नाम javap पर पारित करने की आवश्यकता है। (: ": Javap इस प्लेटफ़ॉर्म पर अनुपलब्ध।" मेरे लिए repl से काम नहीं करता है) तो उदाहरण के लिए, एक कमांड लाइन से है repl में:

पहले यह classOf का उपयोग कर लेने के

scala> classOf[List[_]] 
res2: java.lang.Class[List[_]] = class scala.collection.immutable.List 

फिर javap का उपयोग , मेरा मानना ​​है कि आपको क्लासपाथ निर्दिष्ट करने की आवश्यकता नहीं है:

d:\bin\scala\scala-2.9.1-1\lib>javap -classpath scala-library.jar "scala.collection.immutable.List" 

लेकिन मुझे संदेह है कि यह आपकी मदद करेगा। शायद आप गतिशील भाषाओं में उपयोग करने के लिए उपयोग की जाने वाली तकनीकों का उपयोग करने की कोशिश कर रहे हैं। मैं शायद ही कभी स्केल में प्रतिलिपि का उपयोग करता हूं (इसे अक्सर जावास्क्रिप्ट में उपयोग करते समय)। एक आईडीई और स्रोत मेरे सभी हैं।

5

जावप काम करता है, लेकिन आप इसे scala.Predef.List पर इंगित कर रहे हैं, जो type है, class नहीं। इसे scala.collection.immutable.List पर इंगित करें।

अब, अधिकांश भाग के लिए केवल एक मूल्य दर्ज करना और परिणाम का प्रकार क्या है पर्याप्त है। :type का उपयोग कभी-कभी सहायक हो सकता है।मुझे लगता है कि getClass का उपयोग करना इसके बारे में जाने का एक बहुत बुरा तरीका है, हालांकि।

इसके अलावा, आप कभी-कभी प्रकार और मूल्यों को मिश्रित कर रहे हैं। एक

scala> classOf[`::`[Int]] res81: java.lang.Class[::[Int]] = class 
scala.collection.immutable.$colon$colon 

वस्तुओं और वर्गों एक ही बात है, वास्तव में नहीं हैं, और, वहाँ है:

scala> `::`.getClass res79: java.lang.Class[_ <: object 
scala.collection.immutable.::] = class 
scala.collection.immutable.$colon$colon$ 

और यहाँ आप वर्ग :: का संदर्भ लें: उदाहरण के लिए, यहाँ आप वस्तु :: को देखें वस्तुओं और कक्षाओं के समान पैटर्न, उनके नाम के लिए एक विशिष्ट नाम के साथ: साथी।

के बजाय dir, बस टैब पूरा होने का उपयोग करें:

scala> "abc". 
+      asInstanceOf   charAt    codePointAt   codePointBefore  codePointCount 
compareTo    compareToIgnoreCase concat    contains    contentEquals   endsWith 
equalsIgnoreCase  getBytes    getChars    indexOf    intern    isEmpty 
isInstanceOf   lastIndexOf   length    matches    offsetByCodePoints regionMatches 
replace    replaceAll   replaceFirst   split     startsWith   subSequence 
substring    toCharArray   toLowerCase   toString    toUpperCase   trim 

scala> "abc".compareTo 
compareTo    compareToIgnoreCase 

scala> "abc".compareTo 
          def compareTo(String): Int 

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

वहां अन्य सामान भी हैं - :help को देखना सुनिश्चित करें, और देखें कि क्या उपलब्ध है।

डॉक्स केवल स्केलैड एपीआई के माध्यम से उपलब्ध हैं। इसे ब्राउज़र पर खोलें, और इसकी खोज को कक्षाओं और विधियों को तुरंत ढूंढने की क्षमता का उपयोग करें। साथ ही, ध्यान दें कि, जावा के विपरीत, आपको विधि का विवरण प्राप्त करने के लिए विरासत सूची के माध्यम से नेविगेट करने की आवश्यकता नहीं है।

और वे प्रतीकों के लिए पूरी तरह से ठीक खोज करते हैं। मुझे संदेह है कि आपने स्कालाडोक पर अधिक समय नहीं बिताया है क्योंकि वहां अन्य दस्तावेज़ उपकरण अभी तक नहीं हैं। जावाडोक दिमाग में आता है - यह पैकेज और कक्षाओं के माध्यम से भयानक ब्राउज़िंग है।

यदि आपके पास विशिष्ट प्रश्न स्टैक ओवरफ़्लो शैली हैं, तो प्रतीकों के साथ खोजने के लिए Symbol Hound का उपयोग करें।

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

मैंने बहुत कम शक्तिशाली आरईपीएल और एक बहुत गरीब स्कैलाडोक के साथ किया है - वे एक साथ काम करते हैं। अनुमोदित, मैं टैब-पूर्ण होने पर अपने हाथों को पाने के लिए ट्रंक (अब हेड) पर छोड़ दिया।

+0

पर क्लिक न करें, मुझे टैब पूर्ण होने या पावर मोड या अलग-अलग सूचियों के बारे में पता नहीं था। आपका संदेश उस पर जोर देता है जो मैंने ऊपर कहा था कि इसमें कोई भी स्पष्ट दस्तावेज नहीं है जो मुझे इनमें से किसी भी चीज़ के बारे में बता रहा है। मैं स्कैलाडोक का बहुत उपयोग करता हूं लेकिन आईएमओ इस तरह से आदर्श नहीं है कि आरईपीएल आपको सीधे अपने वर्तमान स्कैला में मौजूद चीज़ों को देखने की सुविधा देता है, कुछ अन्य नहीं। '::' के लिए, मुझे पता है कि एक प्रकार और एक वर्ग दोनों है लेकिन मुद्दा यह है कि यह अक्सर स्पष्ट नहीं होता है, जब आप स्कैला विशेषज्ञ नहीं होते हैं, और आपको इसे पहले से नहीं जानना चाहिए आरईपीएल का उपयोग करते समय। –

4

ध्यान दें कि scala 2.11.8 New tab-completion in the Scala REPL प्रकार की खोज/खोज को सुविधाजनक बना सकता है।

अब यह शामिल हैं:

  • केमलकेस पूरा होने:
    कोशिश:
    (l: List[Int]).rroटैब,
    इसे करने के लिए फैलता है: किसी भी CamelCased भाग लिखने पर
    (l: List[Int]).reduceRightOption

  • सदस्यों का पता लगाएं नाम का:
    कोशिश:
    classOf[String].typटैब, getAnnotationsByType, getComponentType और दूसरों

  • टाइपिंग प्राप्त बिना पूर्ण सेम ही टिककर खेल पाने के लिए:
    कोशिश:
    (d: java.util.Date).dayटैब

  • प्रेस टैब दो बार विधि हस्ताक्षर देखने के लिए:
    कोशिश:
    List(1,2,3).partटैब,
    जो करने के लिए पूरा करता है:
    List(1,2,3).partition;
    प्रेस टैब प्रदर्शित करने के लिए फिर से:
    def partition(p: Int => Boolean): (List[Int], List[Int])

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