स्काला टाइप प्रोग्रामिंग संसाधन


102

इस प्रश्न के अनुसार , स्काला का प्रकार प्रणाली ट्यूरिंग पूर्ण है । वे कौन से संसाधन उपलब्ध हैं जो एक नवागंतुक को टाइप-स्तरीय प्रोग्रामिंग की शक्ति का लाभ उठाने में सक्षम बनाते हैं?

यहां वे संसाधन हैं जो मैंने अब तक पाए हैं:

ये संसाधन महान हैं, लेकिन मुझे लगता है कि मैं मूल बातें याद कर रहा हूं, और इसलिए कोई ठोस आधार नहीं है जिस पर निर्माण करना है। उदाहरण के लिए, टाइप परिभाषाएँ कहाँ है? मैं किस प्रकार के ऑपरेशन कर सकता हूं?

क्या कोई अच्छा परिचयात्मक संसाधन हैं?


व्यक्तिगत रूप से, मुझे यह धारणा मिली कि जो कोई स्काला में टाइप-स्तरीय प्रोग्रामिंग करना चाहता है, वह पहले से ही जानता है कि स्कैला में प्रोग्रामिंग करना कितना उचित है। यहां तक ​​कि अगर इसका मतलब है कि मैं उन लेखों का एक शब्द नहीं समझता हूं जो आप से जुड़े हैं :-)
Jörg W Mittag

जवाबों:


140

अवलोकन

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

उदाहरण

टाइप-स्तरीय प्रोग्रामिंग में दो मुख्य प्रतिमान हैं: "ऑब्जेक्ट-ओरिएंटेड" और "फंक्शनल"। यहाँ से जुड़े अधिकांश उदाहरण ऑब्जेक्ट-ओरिएंटेड प्रतिमान का अनुसरण करते हैं।

ऑब्जेक्ट-ओरिएंटेड प्रतिमान में टाइप-स्तरीय प्रोग्रामिंग का एक अच्छा, काफी सरल उदाहरण है , जिसे लैम्ब्डा कैलकुलस के कार्यान्वयन में पाया जा सकता है, जिसे यहां दोहराया गया है:

// Abstract trait
trait Lambda {
  type subst[U <: Lambda] <: Lambda
  type apply[U <: Lambda] <: Lambda
  type eval <: Lambda
}

// Implementations
trait App[S <: Lambda, T <: Lambda] extends Lambda {
  type subst[U <: Lambda] = App[S#subst[U], T#subst[U]]
  type apply[U] = Nothing
  type eval = S#eval#apply[T]
}

trait Lam[T <: Lambda] extends Lambda {
  type subst[U <: Lambda] = Lam[T]
  type apply[U <: Lambda] = T#subst[U]#eval
  type eval = Lam[T]
}

trait X extends Lambda {
  type subst[U <: Lambda] = U
  type apply[U] = Lambda
  type eval = X
}

जैसा कि उदाहरण में देखा जा सकता है, टाइप-स्तरीय प्रोग्रामिंग आय के लिए वस्तु-उन्मुख प्रतिमान निम्नानुसार है:

  • पहला: विभिन्न अमूर्त प्रकार के फ़ील्ड के साथ एक अमूर्त विशेषता को परिभाषित करें (एक सार फ़ील्ड के लिए नीचे देखें)। यह गारंटी देने के लिए एक टेम्प्लेट है कि कुछ प्रकार के फ़ील्ड बिना कार्यान्वयन के सभी कार्यान्वयन में मौजूद हैं। लैम्ब्डा पथरी उदाहरण में, को यह मेल खाती है trait Lambdaकि गारंटी देता है कि निम्न प्रकार के होते हैं: subst, apply, औरeval
  • अगला: उन उपग्रहों को परिभाषित करें जो अमूर्त विशेषता का विस्तार करते हैं और विभिन्न अमूर्त प्रकार के क्षेत्रों को लागू करते हैं
    • अक्सर, इन उपग्रहों को तर्कों के साथ मानकीकृत किया जाएगा। लैम्ब्डा कैलकुलस उदाहरण में, उपप्रकार वे होते हैं trait App extends Lambdaजो दो प्रकारों से ( Sऔर T, दोनों के उप-प्रकार होने चाहिए Lambda), trait Lam extends Lambdaएक प्रकार से मानकीकृत ( T), औरtrait X extends Lambda (जो कि पैरामीटर नहीं है)।
    • उपक्षेत्र के प्रकार के मापदंडों का हवाला देकर और कभी-कभी हैश ऑपरेटर के माध्यम से अपने प्रकार के क्षेत्रों को संदर्भित करके टाइप फ़ील्ड लागू #किया जाता है : (जो डॉट ऑपरेटर के समान है: .मूल्यों के लिए)। Appलैम्ब्डा कैलकुलस उदाहरण के लक्षण में, प्रकार evalनिम्नानुसार लागू किया गया है type eval = S#eval#apply[T]:। यह अनिवार्य रूप evalसे विशेषता के पैरामीटर के प्रकार को Sबुला रहा है, और परिणाम पर applyपैरामीटर के साथ कॉल कर रहा है T। ध्यान दें, Sएक evalप्रकार की गारंटी दी जाती है क्योंकि पैरामीटर इसे उप-प्रकार निर्दिष्ट करता है Lambda। इसी तरह, परिणाम का evalएक applyप्रकार होना चाहिए , क्योंकि यह एक उपप्रकार के Lambdaरूप में निर्दिष्ट है, जैसा कि अमूर्त विशेषता में निर्दिष्ट है Lambda

फ़ंक्शनल प्रतिमान में बहुत सारे मानकीकृत प्रकार के कंस्ट्रक्टर को परिभाषित करना शामिल होता है, जो लक्षण में एक साथ समूहीकृत नहीं होते हैं।

मूल्य-स्तरीय प्रोग्रामिंग और टाइप-स्तरीय प्रोग्रामिंग के बीच तुलना

  • अमूर्त वर्ग
    • मूल्य-स्तर: abstract class C { val x }
    • टाइप-स्तर: trait C { type X }
  • पथ निर्भर प्रकार
    • C.x (वस्तु सी में फ़ंक्शन फ़ील्ड मान / फ़ंक्शन x)
    • C#x (विशेषता सी में फ़ील्ड प्रकार x संदर्भित करना)
  • फ़ंक्शन हस्ताक्षर (कोई कार्यान्वयन नहीं)
    • मूल्य-स्तर: def f(x:X) : Y
    • प्रकार-स्तर: type f[x <: X] <: Y(इसे "टाइप कंस्ट्रक्टर" कहा जाता है और आमतौर पर अमूर्त विशेषता में होता है)
  • समारोह कार्यान्वयन
    • मूल्य-स्तर: def f(x:X) : Y = x
    • टाइप-स्तर: type f[x <: X] = x
  • सशर्त,
  • समानता की जाँच करना
    • मूल्य-स्तर: a:A == b:B
    • टाइप-स्तर: implicitly[A =:= B]
    • मूल्य-स्तर: रनवे पर एक इकाई परीक्षण के माध्यम से जेवीएम में होता है (यानी कोई रनटाइम त्रुटियाँ):
      • निबंध में एक जोर है: assert(a == b)
    • टाइप-लेवल: कंपाइलर के माध्यम से कंपाइलर में होता है (यानी कोई कंपाइलर एरर नहीं):
      • संक्षेप में एक प्रकार की तुलना है: उदाहरण के लिए implicitly[A =:= B]
      • A <:< B, संकलन करता है, केवल अगर Aइसका उप-प्रकार हैB
      • A =:= B, संकलन करता है, केवल अगर Aइसका उप-प्रकार है Bऔर Bइसका उप-प्रकार हैA
      • A <%< B, ("के रूप में देखने योग्य") केवल तभी Aदेखा जा सकता है जब देखने योग्य हो B(जैसे कि Aएक उप-प्रकार से एक अंतर्निहित रूपांतरण है B)
      • एक उदाहरण
      • अधिक तुलना ऑपरेटरों

प्रकारों और मूल्यों के बीच रूपांतरण

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

    • उदाहरण के लिए val x:A = null, Aआप किस प्रकार की परवाह करते हैं
  • टाइप-इरेज़र के कारण, पैरामीटर किए गए प्रकार सभी समान दिखते हैं। इसके अलावा, (जैसा कि ऊपर उल्लेख किया गया है) आप जिन मूल्यों के साथ काम कर रहे हैं, वे सभी हो सकते हैं null, और इसलिए वस्तु प्रकार पर कंडीशनिंग (जैसे एक मैच स्टेटमेंट के माध्यम से) अप्रभावी है।

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

इस उदाहरण पर विचार करें ( मेटस्कला और सर्वनाश से लिया गया ):

sealed trait Nat
sealed trait _0 extends Nat
sealed trait Succ[N <: Nat] extends Nat

यहां आपके पास प्राकृतिक संख्याओं की एक पीनो एन्कोडिंग है। यही है, आपके पास प्रत्येक गैर-नकारात्मक पूर्णांक के लिए एक प्रकार है: 0 के लिए एक विशेष प्रकार, अर्थात् _0; और शून्य से अधिक के प्रत्येक पूर्णांक में एक प्रकार का रूप होता है Succ[A], जहां एक प्रकार से Aछोटे पूर्णांक का प्रतिनिधित्व होता है। उदाहरण के लिए, 2 का प्रतिनिधित्व करने वाला प्रकार होगा: Succ[Succ[_0]](उत्तराधिकारी शून्य का प्रतिनिधित्व करने वाले प्रकार पर दो बार लागू होता है)।

हम अधिक सुविधाजनक संदर्भ के लिए विभिन्न प्राकृतिक संख्याओं को उर्फ ​​कर सकते हैं। उदाहरण:

type _3 = Succ[Succ[Succ[_0]]]

(यह valएक फ़ंक्शन के परिणाम के रूप में परिभाषित करने के लिए बहुत कुछ है ।)

अब, मान लीजिए कि हम एक मान-स्तरीय फ़ंक्शन को परिभाषित करना चाहते हैं, def toInt[T <: Nat](v : T)जो एक तर्क मान में लेता है v, जो कि Natपूर्णांक को प्राकृतिक vप्रकार का प्रतिनिधित्व करने वाले पूर्णांक के रूप में देता है और देता है । उदाहरण के लिए, यदि हमारे पास मूल्य val x:_3 = null( nullप्रकार का Succ[Succ[Succ[_0]]]) है, तो हम चाहेंगेtoInt(x) वापस लौटना3

लागू करने के लिए toInt, हम निम्न वर्ग का उपयोग करने जा रहे हैं:

class TypeToValue[T, VT](value : VT) { def getValue() = value }

हम नीचे देखेंगे के रूप में, एक वस्तु वर्ग का निर्माण किया जाएगा TypeToValueप्रत्येक के लिए Natसे _0ऊपर (जैसे) के लिए _3, और प्रत्येक इसी प्रकार (यानी के मूल्य में प्रतिनिधित्व स्टोर करेगा TypeToValue[_0, Int]मान संग्रहीत होगा 0, TypeToValue[Succ[_0], Int]मान संग्रहीत होगा 1, आदि)। ध्यान दें, TypeToValueदो प्रकारों से परिचालित किया जाता है: Tऔर VTTउस प्रकार से मेल खाती है जिसे हम (हमारे उदाहरण में Nat) मान निर्दिष्ट करने का प्रयास कर रहे हैं, और VTउस प्रकार के मान से मेल खाते हैं जिसे हम इसे निर्दिष्ट कर रहे हैं (हमारे उदाहरण में,Int ) ।

अब हम निम्नलिखित दो निहित परिभाषाएँ बनाते हैं:

implicit val _0ToInt = new TypeToValue[_0, Int](0)
implicit def succToInt[P <: Nat](implicit v : TypeToValue[P, Int]) = 
     new TypeToValue[Succ[P], Int](1 + v.getValue())

और हम toIntनिम्नानुसार लागू करते हैं:

def toInt[T <: Nat](v : T)(implicit ttv : TypeToValue[T, Int]) : Int = ttv.getValue()

यह समझने के लिए कि कैसे toIntकाम करता है, आइए विचार करें कि यह कुछ इनपुट पर क्या करता है:

val z:_0 = null
val y:Succ[_0] = null

जब हम कॉल करते हैं toInt(z), तो कंपाइलर ttvटाइप के एक निहित तर्क की तलाश करता है TypeToValue[_0, Int](क्योंकि zटाइप का है _0)। यह ऑब्जेक्ट ढूंढता है _0ToInt, यह getValueइस ऑब्जेक्ट की विधि को कॉल करता है और वापस हो जाता है0 । ध्यान देने वाली महत्वपूर्ण बात यह है कि हमने उस प्रोग्राम को निर्दिष्ट नहीं किया है जिसका उपयोग करने के लिए ऑब्जेक्ट को संकलित किया गया है।

अब विचार करते हैं toInt(y)। इस बार, संकलक ttvप्रकार के निहित तर्क के लिए लग रहा है TypeToValue[Succ[_0], Int](चूंकि yप्रकार का है Succ[_0])। यह फ़ंक्शन को ढूंढता है succToInt, जो उचित प्रकार ( TypeToValue[Succ[_0], Int]) का ऑब्जेक्ट वापस कर सकता है और इसका मूल्यांकन कर सकता है। यह फ़ंक्शन अपने आप में एक अंतर्निहित तर्क ( v) का प्रकार लेता है TypeToValue[_0, Int](अर्थात, TypeToValueजहां पहला प्रकार का पैरामीटर एक कम है Succ[_])। संकलक आपूर्ति _0ToInt(जैसा कि toInt(z)ऊपर के मूल्यांकन में किया गया था ), और मूल्य के साथ succToIntएक नई TypeToValueवस्तु का निर्माण करता है 1। फिर, यह ध्यान रखना महत्वपूर्ण है कि संकलक इन सभी मूल्यों को अंतर्निहित रूप से प्रदान कर रहा है, क्योंकि हमारे पास स्पष्ट रूप से उन तक पहुंच नहीं है।

अपने काम की जाँच कर रहा है

यह सत्यापित करने के कई तरीके हैं कि आपकी टाइप-स्तरीय गणनाएँ वह कर रही हैं जो आप अपेक्षा करते हैं। यहाँ कुछ दृष्टिकोण हैं। दो प्रकार बनाएं Aऔर B, जिसे आप सत्यापित करना चाहते हैं, बराबर हैं। फिर जाँच करें कि निम्नलिखित संकलन:

वैकल्पिक रूप से, आप टाइप को एक मान में बदल सकते हैं (जैसा कि ऊपर दिखाया गया है) और मानों का रनटाइम चेक करें। जैसे assert(toInt(a) == toInt(b)), aप्रकार Aका bहै और प्रकार का है B

अतिरिक्त संसाधन

उपलब्ध कंस्ट्रक्शन का पूरा सेट स्कैला संदर्भ मैनुअल (पीडीएफ) के प्रकार अनुभाग में पाया जा सकता है ।

Adriaan Moors प्रकार के निर्माणकर्ताओं और संबंधित विषयों के बारे में कई अकादमिक पत्र हैं, जिसमें scala के उदाहरण हैं:

एपोकैलिस्प एक ब्लॉग है जिसमें स्कैला में टाइप-स्तरीय प्रोग्रामिंग के कई उदाहरण हैं।

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

मेटास्कला स्केला के लिए एक प्रकार-स्तरीय पुस्तकालय है, जिसमें प्राकृतिक संख्या, बूलियन, यूनिट, एचएलआईटीए आदि के लिए मेटा प्रकार शामिल हैं। यह एक परियोजना है, जोपर नोर्डबर्ग (उनके ब्लॉग) द्वारा बनाई गई है।

Michid (ब्लॉग) कुछ कमाल (अन्य जवाब से) स्काला में टाइप-स्तरीय प्रोग्रामिंग के उदाहरण हैं:

देबाशीष घोष (ब्लॉग) के पास कुछ प्रासंगिक पोस्ट हैं:

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


12

बस दिलचस्प ब्लॉग के लिए धन्यवाद कहना चाहता था; मैं कुछ समय से इसका पालन कर रहा हूं और विशेष रूप से ऊपर बताई गई अंतिम पोस्ट ने महत्वपूर्ण गुणों के बारे में मेरी समझ को तेज कर दिया है जो एक वस्तु उन्मुख भाषा के लिए एक प्रकार की प्रणाली होनी चाहिए। तो धन्यवाद!
ज़ैक स्नो



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