scala - वस्तुओं/प्रकारों/आदि की जांच कैसे करें। स्काला आरईपीएल से?




read-eval-print-loop exploratory (3)

आपको javap करने के लिए पूरी तरह से योग्य वर्ग नाम पास करना javap

पहले इसे लेने का उपयोग करें classOf :

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

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

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

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

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

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

  1. यदि foo एक मान है (जिसमें संभवतः चरों और साथी वस्तुओं और अन्य स्काला object एस में संग्रहीत चीजें शामिल हैं), तो आप सीधे foo मूल्यांकन कर सकते हैं। आपको परिणाम का प्रकार और मूल्य बताना चाहिए। कभी-कभी परिणाम सहायक होता है, कभी-कभी नहीं।
  2. यदि foo एक मान है, तो आप इसका उपयोग कर सकते हैं :type foo इसके प्रकार को प्राप्त करने के लिए :type foo टाइप करें। (जरूरी नहीं कि ज्ञानवर्धक हो।) यदि आप किसी फ़ंक्शन कॉल पर इसका उपयोग करते हैं, तो आपको फ़ंक्शन को कॉल किए बिना, रिटर्न मान का प्रकार मिलता है।
  3. यदि foo एक मान है, तो आप इसका वर्ग प्राप्त करने के लिए foo.getClass का उपयोग कर सकते हैं। (अक्सर पिछले की तुलना में अधिक ज्ञानवर्धक, लेकिन किसी वस्तु का वर्ग उसके प्रकार से कैसे भिन्न होता है?)
  4. एक क्लास foo , आप classOf[foo] उपयोग कर सकते हैं, हालांकि यह स्पष्ट नहीं है कि परिणाम का क्या मतलब है।
  5. सैद्धांतिक रूप से, आप उपयोग कर सकते हैं :javap foo एक वर्ग को अलग करने के लिए :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 = scala.Predef$@3cd41115

scala> :type Predef
type

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

इसका क्या मतलब है? Predef का type केवल type क्यों है, जबकि वर्ग scala.Predef$ ? मैं इकट्ठा करता हूं कि $ वह तरीका है जो साथी वस्तुओं को जावा में Predef जाता है ... लेकिन Google पर स्काला डॉक्स मुझे बताता है कि Predef object Predef extends LowPriorityImplicits - मैं इसे REPL से कैसे object 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. क्या सच में Scala वस्तुओं, वर्गों, विधियों, आदि की समझ बनाने के लिए REPL का उपयोग करने के सही स्काला विशेषज्ञों से सबसे अच्छा तरीका है, या कम से कम उनकी जाँच करें जैसे कि REPL से किया जा सकता है?
  2. मैं कैसे प्राप्त :javap निर्मित सामान के लिए REPL से काम कर :javap ? (क्या यह डिफ़ॉल्ट रूप से काम नहीं करना चाहिए?)

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


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

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

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

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

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

स्केलास स्वयं के प्रतिबिंब पुस्तकालय के रूप में 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)

नए प्रतिबिंब पुस्तकालय के लिए प्रलेखन अभी भी गायब है, लेकिन प्रगति में है। यह REPL के अंदर एक आसान तरीके से स्केलक का उपयोग करने की अनुमति देता है:

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] = scala.tools.reflect.ToolBoxFactory$ToolBoxImpl@32f7fa37

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)

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

scala> :type Predef
scala.Predef.type

स्केलडॉक कुछ प्रकार-पदानुक्रम ग्राफ (टाइप-पदानुक्रम पर क्लिक करें) प्राप्त करेगा।

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

// 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 कहा जाता है।

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

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

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{
...

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

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

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

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


ध्यान दें कि स्कैला आरईपीएल में स्कैला 2.11.8 नया टैब-पूरा होने से खोज / खोज की सुविधा मिल सकती है।

अब इसमें शामिल हैं:

  • CamelCase पूरा करना:
    प्रयत्न:
    (l: List[Int]).rro टैब ,
    इसका विस्तार होता है:
    (l: List[Int]).reduceRightOption

  • नाम के किसी भी CamelCased भाग टाइप करके सदस्यों का पता लगाएं:
    प्रयत्न:
    classOf[String].typ TAB , getAnnotationsByType पाने के लिए, getComponentType और अन्य

  • टाइपिंग के बिना पूरा बीन गेटर्स:
    प्रयत्न:
    (d: java.util.Date).day TAB

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





exploratory