किसी भी कारण से स्केला स्पष्ट रूप से निर्भर प्रकारों का समर्थन नहीं करता है?


109

पथ पर निर्भर प्रकार हैं और मुझे लगता है कि स्काला में एपिग्राम या एजडा जैसी भाषाओं की लगभग सभी विशेषताओं को व्यक्त करना संभव है, लेकिन मैं सोच रहा हूं कि स्काला इस बात का अधिक स्पष्ट रूप से समर्थन क्यों नहीं करता है, क्योंकि यह अन्य क्षेत्रों में बहुत अच्छी तरह से कहता है (कहते हैं , DSLs)? मुझे कुछ भी याद आ रहा है जैसे "यह आवश्यक नहीं है"?


3
खैर, स्काला के डिजाइनरों का मानना ​​है कि बारेंड्रेगेट लैंबडा क्यूब टाइप थ्योरी का ऑल-एंड-एंड-ऑल नहीं है। वह कारण हो भी सकता है और नहीं भी।
जोर्ग डब्ल्यू मित्तग

8
@ JörgWMittag लाम्डा क्यूब क्या है? जादू के उपकरण के कुछ प्रकार?
अशोकन ख। नाज़री

@ ashy_32bit बारेंड्रेगेट के पेपर "सामान्यीकृत प्रकार सिस्टम का परिचय" यहां देखें: diku.dk/hjemmesider/ansatte/henglein/papers/barendregt1991.pdf
iainmcgin

जवाबों:


151

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

आश्रित प्रकारों के लिए स्काला का आंतरिक समर्थन पथ-निर्भर प्रकारों के माध्यम से है । ये एक प्रकार को ऑब्जेक्ट के माध्यम से चयनकर्ता पथ पर निर्भर करने की अनुमति देते हैं- (जैसे। मूल्य-) ग्राफ जैसे,

scala> class Foo { class Bar }
defined class Foo

scala> val foo1 = new Foo
foo1: Foo = Foo@24bc0658

scala> val foo2 = new Foo
foo2: Foo = Foo@6f7f757

scala> implicitly[foo1.Bar =:= foo1.Bar] // OK: equal types
res0: =:=[foo1.Bar,foo1.Bar] = <function1>

scala> implicitly[foo1.Bar =:= foo2.Bar] // Not OK: unequal types
<console>:11: error: Cannot prove that foo1.Bar =:= foo2.Bar.
              implicitly[foo1.Bar =:= foo2.Bar]

मेरे विचार में, उपरोक्त प्रश्न का उत्तर देने के लिए पर्याप्त होना चाहिए "क्या स्काला एक भरोसेमंद रूप से टाइप की गई भाषा है?" सकारात्मक में: यह स्पष्ट है कि यहाँ हमारे पास वे प्रकार हैं जो उन मूल्यों से अलग हैं जो उनके उपसर्ग हैं।

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

शब्दावली के बावजूद, निर्भर योग प्रकार (जिसे सिग्मा प्रकार के रूप में भी जाना जाता है) बस मूल्यों की एक जोड़ी है जहां दूसरे मूल्य का प्रकार पहले मूल्य पर निर्भर है। यह सीधे स्काला में प्रतिनिधित्व करने योग्य है,

scala> trait Sigma {
     |   val foo: Foo
     |   val bar: foo.Bar
     | }
defined trait Sigma

scala> val sigma = new Sigma {
     |   val foo = foo1
     |   val bar = new foo.Bar
     | }
sigma: java.lang.Object with Sigma{val bar: this.foo.Bar} = $anon$1@e3fabd8

और वास्तव में, यह आश्रित विधि प्रकारों के एन्कोडिंग का एक महत्वपूर्ण हिस्सा है, जो 2.10 से पहले स्काला में 'बेकरी ऑफ डूम' से बचने के लिए आवश्यक है (या पहले प्रायोगिक-योध् य-विधि प्रकार स्काला संकलक विकल्प के माध्यम से)।

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

scala> trait Pi[T] { type U }
defined trait Pi

हम एक बहुरूपिक विधि को परिभाषित कर सकते हैं जो इस प्रकार का उपयोग करता है,

scala> def depList[T](t: T)(implicit pi: Pi[T]): List[pi.U] = Nil
depList: [T](t: T)(implicit pi: Pi[T])List[pi.U]

( pi.Uपरिणाम प्रकार में पथ-निर्भर प्रकार के उपयोग पर ध्यान दें List[pi.U])। प्रकार T के मान को देखते हुए, यह फ़ंक्शन उस विशेष T मान के अनुरूप प्रकार के मानों की एक (n खाली) सूची लौटाएगा।

आइए अब कुछ कार्यात्मक मूल्यों और निहित गवाहों को परिभाषित करते हैं जो कार्यात्मक संबंधों को हम पकड़ना चाहते हैं,

scala> object Foo
defined module Foo

scala> object Bar
defined module Bar

scala> implicit val fooInt = new Pi[Foo.type] { type U = Int }
fooInt: java.lang.Object with Pi[Foo.type]{type U = Int} = $anon$1@60681a11

scala> implicit val barString = new Pi[Bar.type] { type U = String }
barString: java.lang.Object with Pi[Bar.type]{type U = String} = $anon$1@187602ae

और अब यहाँ क्रिया में हमारा पाई-टाइप-उपयोग फ़ंक्शन है,

scala> depList(Foo)
res2: List[fooInt.U] = List()

scala> depList(Bar)
res3: List[barString.U] = List()

scala> implicitly[res2.type <:< List[Int]]
res4: <:<[res2.type,List[Int]] = <function1>

scala> implicitly[res2.type <:< List[String]]
<console>:19: error: Cannot prove that res2.type <:< List[String].
              implicitly[res2.type <:< List[String]]
                    ^

scala> implicitly[res3.type <:< List[String]]
res6: <:<[res3.type,List[String]] = <function1>

scala> implicitly[res3.type <:< List[Int]]
<console>:19: error: Cannot prove that res3.type <:< List[Int].
              implicitly[res3.type <:< List[Int]]

(ध्यान दें कि यहाँ हम स्काला का उपयोग करने <:<के बजाय उप-प्रकार-साक्षी ऑपरेटर =:=क्योंकि res2.typeऔर res3.typeसिंगलटन प्रकार और प्रकार हम आरएचएस पर पुष्टि कर रहे हैं की तुलना में इसलिए अधिक सटीक हैं)।

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

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

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


8
मीलों, इस बहुत विस्तृत जवाब के लिए धन्यवाद। मैं एक बात को लेकर थोड़ा उत्सुक हूँ, हालाँकि। अपने उदाहरणों में से कोई भी पहली नज़र में विशेष रूप से हास्केल में व्यक्त करना असंभव लगता है; क्या आप तब दावा कर रहे हैं कि हास्केल भी एक भरोसेमंद भाषा है?
जोनाथन स्टर्लिंग

8
मैं downvoted क्योंकि मैं तकनीक यहाँ तकनीक मैकब्राइड के में वर्णित से सार में भेद नहीं कर सकते "यह Faking" citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.22.2636 - यानी इन अनुकरण करने के लिए तरीके हैं निर्भर प्रकार, उन्हें सीधे प्रदान नहीं करते हैं।
sclv

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

4
नहीं। सुनिश्चित करें कि आप वस्तुओं से बंधे हो सकते हैं (यह मॉड्यूल के रूप में वस्तुओं का एक परिणाम है)। लेकिन आप मूल्य-स्तर के गवाहों का उपयोग किए बिना इन प्रकारों पर गणना नहीं कर सकते। वास्तव में =: = स्वयं एक मूल्य-स्तरीय गवाह है! आप अभी भी इसे फेक कर रहे हैं, जैसे आप हास्केल में हैं, या शायद अधिक।
sclv

9
स्काला का =: = मूल्य-स्तर नहीं है, यह एक प्रकार का निर्माता है - इसके लिए एक मूल्य यहाँ है: github.com/scala/scala/blob/v2.10.3/src/library/scala/… , और प्रतीत नहीं होता विशेष रूप से Agda और Idris: refl जैसी निर्भर-टाइप की गई भाषाओं में समानता के प्रस्ताव के लिए एक गवाह से अलग। (देखें www2.tcs.ifi.lmu.de/~abel/Equality.pdf खंड 2, और eb.host.cs.st-andrews.ac.uk/writings/idris-tutorial.pdf खंड: 8.1, क्रमशः।)
pdxleif

6

मुझे लगता है कि ऐसा इसलिए है क्योंकि (जैसा कि मैं अनुभव से जानता हूं, कॉक प्रूफ असिस्टेंट में आश्रित प्रकार का उपयोग किया गया है, जो पूरी तरह से उनका समर्थन करता है, लेकिन अभी भी बहुत सुविधाजनक तरीके से नहीं) निर्भर प्रकार एक बहुत ही उन्नत प्रोग्रामिंग भाषा सुविधा है जो वास्तव में कठिन है सही हो - और व्यवहार में जटिलता के एक घातीय प्रहार का कारण बन सकता है। वे अभी भी कंप्यूटर विज्ञान अनुसंधान का एक विषय हैं।


क्या आप मुझे आश्रित प्रकार (शायद एक कड़ी) के लिए कुछ सैद्धांतिक पृष्ठभूमि देने के लिए पर्याप्त होंगे?
अशोकन ख। नाज़री

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

3

मेरा मानना ​​है कि स्काला के पथ-निर्भर प्रकार केवल types-प्रकार का प्रतिनिधित्व कर सकते हैं, लेकिन's-प्रकार के नहीं। यह:

trait Pi[T] { type U }

वास्तव में एक type प्रकार नहीं है। परिभाषा के अनुसार, a-type, या आश्रित उत्पाद, एक फ़ंक्शन है जिसका परिणाम प्रकार तर्क मान पर निर्भर करता है, सार्वभौमिक मात्रा का प्रतिनिधित्व करता है, अर्थात Bx: A, B (x)। उपरोक्त मामले में, हालांकि, यह केवल टाइप T पर निर्भर करता है, लेकिन इस प्रकार के कुछ मूल्य पर नहीं। पाई गुण स्वयं एक a-प्रकार है, एक अस्तित्वमान मात्रात्मक, यानी Ax: A, B (x)। इस मामले में ऑब्जेक्ट का सेल्फ-रेफरेंस क्वांटिफाइड वेरिएबल की तरह काम कर रहा है। जब इसे अंतर्निहित पैरामीटर के रूप में पारित किया जाता है, हालांकि, यह एक साधारण प्रकार के फ़ंक्शन में कम हो जाता है, क्योंकि यह टाइप-वार हल हो जाता है। स्काला में आश्रित उत्पाद के लिए एन्कोडिंग निम्नलिखित की तरह लग सकता है:

trait Sigma[T] {
  val x: T
  type U //can depend on x
}

// (t: T) => (∃ mapping(x, U), x == t) => (u: U); sadly, refinement won't compile
def pi[T](t: T)(implicit mapping: Sigma[T] { val x = t }): mapping.U 

यहाँ अनुपलब्ध टुकड़ा सांख्यिकीय रूप से बाधा क्षेत्र x से अपेक्षित मान t तक की क्षमता है, प्रभावी ढंग से एक समीकरण बनाकर सभी प्रकारों की संपत्ति का प्रतिनिधित्व करता है जो T टाइप कर रहा है। साथ ही हमारे Σ-प्रकार के साथ, दी गई संपत्ति के साथ वस्तु के अस्तित्व को व्यक्त करने के लिए उपयोग किया जाता है। तर्क बनता है, जिसमें हमारा समीकरण सिद्ध होने के लिए एक प्रमेय है।

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


1
मीलों सबिन ने उपरोक्त Piमूल्यों के आधार पर प्रकार बनाने के लिए उपयोग करने का एक उदाहरण दिखाया है ।
लापता

उदाहरण में, depListअर्क प्रकार Uसे Pi[T], प्रकार के लिए चयनित (मान नहीं) t। यह प्रकार केवल सिंगलटन प्रकार होता है, वर्तमान में स्काला सिंगलटन ऑब्जेक्ट्स पर उपलब्ध है और उनके सटीक मानों का प्रतिनिधित्व करता है। उदाहरण Piप्रति एकल ऑब्जेक्ट प्रकार का एक कार्यान्वयन बनाता है , इस प्रकार value- प्रकार के रूप में मूल्य के साथ बाँधना। On-type, दूसरी ओर, एक सूत्र है जो इसके इनपुट पैरामीटर की संरचना से मेल खाता है। संभवतः, स्काला उनके पास नहीं है क्योंकि ibly-प्रकारों को GADT होने के लिए हर पैरामीटर प्रकार की आवश्यकता होती है और स्काला GADTs को अन्य प्रकारों से अलग नहीं करता है।
पी। फ्रोलोव

ठीक है, मैं थोड़ा उलझन में हूं। pi.Uमाइल्स का उदाहरण निर्भर प्रकार के रूप में नहीं गिना जाएगा? यह मूल्य पर है pi
लापताफोरटोर

2
यह वास्तव में निर्भर प्रकार के रूप में गिना जाता है, लेकिन उन लोगों के अलग-अलग स्वाद हैं: type-type ("वहाँ x मौजूद है जैसे कि P (x)", तर्क-वार) और Π-type ("सभी x, P (x) के लिए") । जैसा कि आपने उल्लेख किया है, प्रकार के pi.Uमूल्य पर निर्भर है pi। समस्या को रोकने कि trait Pi[T]एक Π प्रकार बनने से कि हम इसे एक मनमाना तर्क के मूल्य पर निर्भर है (उदाहरण के लिए, नहीं कर सकता है tमें depListप्रकार के स्तर पर है कि तर्क उठाने के बिना)।
पी। फ्रोलोव

1

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

यह इस सवाल का जवाब देने की कोशिश नहीं है कि स्कैड को इदरीस (मैं बहुत कठिन कल्पना करता हूं) में बदल दूंगा या इदरीस के लिए अधिक प्रत्यक्ष समर्थन की तरह एक पुस्तकालय लिखने के लिए (जैसे singletonsहास्केल में होने की कोशिश करता हूं )।

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

स्काला (हस्केल के समान) कई प्रकार की गणनाओं को सांकेतिक शब्दों में बदलना करने में सक्षम हो सकता है। यह पुस्तकालयों द्वारा दिखाया गया है जैसे shapeless। इन पुस्तकालयों यह कुछ वास्तव में प्रभावशाली और चालाक चाल का उपयोग कर। हालांकि, उनका प्रकार स्तर कोड (वर्तमान में) मूल्य स्तर के भावों से काफी अलग है (मुझे लगता है कि हास्केल में कुछ हद तक करीब है)। Idris, IS के प्रकार के स्तर पर मूल्य स्तर की अभिव्यक्ति का उपयोग करने की अनुमति देता है।

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

सत्यापित कोड पर विचार करें। देखें:
https://github.com/idris-lang/Idris-dev/blob/v1.3.0/libs/contrib/Interfaces/Verified.idr
चेकर मोनाडर्स / फन्ने / आवेदक कानूनों के सबूतों की पुष्टि करता है और सबूत वास्तविक के बारे में हैं मोनाड / फनकार / एपेरेटिव के कार्यान्वयन और कुछ एन्कोडेड प्रकार के स्तर के बराबर नहीं जो समान हो सकते हैं या समान नहीं हो सकते हैं। बड़ा सवाल यह है कि हम क्या साबित कर रहे हैं?

वही मुझे चालाक एन्कोडिंग ट्रिक्स का उपयोग करके किया जा सकता है (हास्केल संस्करण के लिए निम्नलिखित देखें, मैंने स्काला के लिए एक नहीं देखा है)
https://blog.jle.im/entry/verified-instances-in-haskell.html
https: // github.com/rpeszek/IdrisTddNotes/wiki/Play_FunctorLaws
प्रकार को छोड़कर इतने जटिल हैं कि कानूनों को देखना कठिन है, मूल्य स्तर के भाव (स्वचालित रूप से लेकिन अभी भी) स्तर की चीजों को परिवर्तित करने के लिए हैं और आपको उस रूपांतरण पर भी भरोसा करने की आवश्यकता है । इस सब में त्रुटि के लिए जगह है जो थोड़े एक प्रमाण सहायक के रूप में संकलक के उद्देश्य को धता बताता है।

(EDITED 2018.8.10) प्रूफ सहायता के बारे में बात करते हुए, इदरिस और स्काला के बीच एक और बड़ा अंतर है। स्काला (या हास्केल) में ऐसा कुछ भी नहीं है जो डायवर्जिंग प्रूफ लिखने से रोक सके:

case class Void(underlying: Nothing) extends AnyVal //should be uninhabited
def impossible() : Void = impossible()

जबकि Idris के पास totalइस तरह के संकलन से कीवर्ड को रोकने वाला कोड है।

मान और प्रकार स्तर कोड (जैसे हास्केल singletons) को एकीकृत करने की कोशिश करने वाली एक स्काला लाइब्रेरी स्कैला के आश्रित प्रकार के समर्थन के लिए एक दिलचस्प परीक्षा होगी। क्या पथ-निर्भर प्रकारों के कारण इस तरह के पुस्तकालय को स्काला में बेहतर बनाया जा सकता है?

मैं खुद उस सवाल का जवाब देने के लिए स्काला के लिए बहुत नया हूं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.