अवलोकन
टाइप-स्तरीय प्रोग्रामिंग पारंपरिक, मूल्य स्तर प्रोग्रामिंग के साथ कई समानताएं है। हालांकि, मूल्य-स्तर प्रोग्रामिंग के विपरीत, जहां गणना रनटाइम पर होती है, टाइप-स्तरीय प्रोग्रामिंग में, गणना संकलन समय पर होती है। मैं टाइप-लेवल पर मूल्य-स्तर और प्रोग्रामिंग पर प्रोग्रामिंग के बीच समानांतर आकर्षित करने का प्रयास करूंगा।
मानदंड
प्रकार स्तरीय प्रोग्रामिंग में दो मुख्य मानदंड हैं: "वस्तु उन्मुख" और "कार्यात्मक"। यहां से जुड़े अधिकांश उदाहरण वस्तु-उन्मुख प्रतिमान का पालन करते हैं।
एक अच्छा, वस्तु उन्मुख प्रतिमान में प्रकार स्तरीय प्रोग्रामिंग के काफी सरल उदाहरण apocalisp के implementation of the lambda calculus में पाया जा सकता है, यहाँ दोहराया:
// 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
।
- अगला: subtraits कि सार विशेषता विस्तार को परिभाषित करने और विभिन्न सार प्रकार क्षेत्रों
- अक्सर, इन subtraits तर्क के साथ parameterized हो जाएगा लागू। लैम्ब्डा पथरी उदाहरण में, उप-प्रकारों
trait App extends Lambda
जो दो प्रकार के साथ पैरामिट्रीकृत है कर रहे हैं, एक प्रकार (T
), और trait X extends Lambda
(जो पैरामिट्रीकृत नहीं है) के साथ trait Lam extends Lambda
पैरामिट्रीकृत (S
और T
, दोनों Lambda
के उपप्रकार होना चाहिए)।
- प्रकार फ़ील्ड को अक्सर उप-पथ के प्रकार पैरामीटर और हेश ऑपरेटर के माध्यम से अपने प्रकार के फ़ील्ड का संदर्भ देकर कार्यान्वित किया जाता है:
#
(जो डॉट ऑपरेटर के समान है: .
मानों के लिए)। लैम्ब्डा कैलकुस उदाहरण के App
की विशेषता में, प्रकार eval
निम्नानुसार कार्यान्वित किया गया है: type eval = S#eval#apply[T]
। यह अनिवार्य रूप से eval
विशेषता के पैरामीटर S
के प्रकार को कॉल कर रहा है, और परिणाम पर T
पैरामीटर के साथ apply
पर कॉल कर रहा है। नोट, S
eval
प्रकार होने की गारंटी है क्योंकि पैरामीटर इसे Lambda
का उप प्रकार निर्दिष्ट करता है। इसी तरह, eval
के परिणाम में apply
प्रकार होना चाहिए, क्योंकि यह Lambda
का उप प्रकार है, जैसा कि अमूर्त विशेषता Lambda
में निर्दिष्ट है।
कार्यात्मक प्रतिमान पैरामिट्रीकृत प्रकार कंस्ट्रक्टर्स कि लक्षण में एक साथ समूहीकृत नहीं कर रहे हैं के बहुत सारे को परिभाषित करने के होते हैं।मूल्य-स्तरीय प्रोग्रामिंग और टाइप-स्तरीय प्रोग्रामिंग के बीच
तुलना
- abstract class
- मूल्य का स्तर:
abstract class C { val x }
- प्रकार स्तरीय:
trait C { type X }
- पथ निर्भर प्रकार
C.x
(संदर्भित फ़ील्ड मान/समारोह वस्तु सी में एक्स)
C#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]
- मूल्य का स्तर: कार्यावधि में एक इकाई परीक्षण के माध्यम से JVM में होता है (अर्थात कोई क्रम त्रुटियों):
assert(a == b)
- प्रकार स्तरीय:
- सार में एक ज़ोर है एक typecheck के माध्यम से संकलक में होता है (यानी कोई संकलक त्रुटियों):
- सार में एक है प्रकार की तुलना करें: उदाहरण के लिए
implicitly[A =:= B]
A <:< B
, संकलित केवल तभी A
, B
A =:= B
की एक उप-प्रकार है संकलित केवल तभी A
B
और B
की एक उप-प्रकार है A
A <%< B
की एक उप-प्रकार, ("के रूप में देखा जा सकता है") है संकलित A
B
(यानीवहाँ B
की एक उप-प्रकार को A
से एक अंतर्निहित रूपांतरण)
- an example
- more comparison operators
प्रकार के बीच परिवर्तित है और महत्व देता
के कई में भूतपूर्व गुणों के माध्यम से परिभाषित प्रकार, अक्सर अमूर्त और मुहरबंद दोनों होते हैं, और इसलिए न तो तुरंत और न ही अज्ञात उप-वर्ग के माध्यम से तुरंत चालू किया जा सकता है।
- उदा: तो यह जब एक मूल्य के स्तर के गणना कर ब्याज की कुछ प्रकार का उपयोग कर एक प्लेसहोल्डर मूल्य के रूप में
null
उपयोग आम है val x:A = null
, जहां A
प्रकार है आपके लिए महत्वपूर्ण हैं
टाइप-विलोपन के कारण, पैरामिट्रीकृत प्रकार सभी एक ही लग रही है। इसके अलावा, (जैसा कि ऊपर उल्लेख) मान आप के साथ काम कर रहे हैं सभी null
हो जाते हैं, और इतने वस्तु प्रकार (उदा एक मैच बयान के माध्यम से) पर कंडीशनिंग अप्रभावी है।
चाल अंतर्निहित कार्यों और मूल्यों का उपयोग करना है। मूल मामला आमतौर पर एक अंतर्निहित मूल्य होता है और रिकर्सिव केस आमतौर पर एक निहित कार्य होता है। दरअसल, टाइप-स्तरीय प्रोग्रामिंग इम्प्लिकेट्स का भारी उपयोग करता है।
sealed trait Nat
sealed trait _0 extends Nat
sealed trait Succ[N <: Nat] extends Nat
यहाँ आप प्राकृतिक संख्या की एक Peano एन्कोडिंग है:
इस उदाहरण (taken from metascala और apocalisp) पर विचार करें। यही है, आपके पास प्रत्येक गैर-ऋणात्मक पूर्णांक के लिए एक प्रकार है: 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
(प्रकार Succ[Succ[Succ[_0]]]
की null
) है, हम toInt(x)
चाहते 3
वापस जाने के लिए होगा।
toInt
लागू करने के लिए, हम निम्नलिखित वर्ग का उपयोग करने के लिए जा रहे हैं:
class TypeToValue[T, VT](value : VT) { def getValue() = value }
के रूप में हम नीचे देखेंगे, एक वस्तु पर निर्भर _0
से प्रत्येक Nat
के लिए वर्ग TypeToValue
से निर्मित किया जाएगा (उदाहरण के लिए) _3
, और प्रत्येक संबंधित प्रकार के मान प्रतिनिधित्व को संग्रहीत करेगा (यानी TypeToValue[_0, Int]
मूल्य 0
, TypeToValue[Succ[_0], Int]
स्टोर करेगा, 1
इत्यादि को संग्रहीत करेगा)। नोट, TypeToValue
दो प्रकारों द्वारा पैरामीटर किया गया है: T
और VT
। T
उस प्रकार से मेल खाता है जिसे हम मान निर्दिष्ट करने की कोशिश कर रहे हैं (हमारे उदाहरण में, 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
जब हमपर कॉल करते हैं, कंपाइलर ttv
प्रकार TypeToValue[_0, Int]
(z
प्रकार _0
) के एक निहित तर्क की तलाश करता है। यह ऑब्जेक्ट _0ToInt
पाता है, यह इस ऑब्जेक्ट की getValue
विधि को कॉल करता है और 0
वापस ले जाता है। ध्यान देने योग्य महत्वपूर्ण बात यह है कि हमने उस प्रोग्राम को निर्दिष्ट नहीं किया जो उपयोग करने के लिए ऑब्जेक्ट करता है, संकलक इसे पूरी तरह से मिला।
अब toInt(y)
पर विचार करें। इस बार, कंपाइलर ttv
प्रकार TypeToValue[Succ[_0], Int]
(y
प्रकार Succ[_0]
) के एक निहित तर्क ttv
की तलाश करता है। यह फ़ंक्शन succToInt
पाता है, जो उपयुक्त प्रकार (TypeToValue[Succ[_0], Int]
) का ऑब्जेक्ट वापस कर सकता है और इसका मूल्यांकन करता है। यह फ़ंक्शन स्वयं TypeToValue[_0, Int]
(यानी TypeToValue
) का एक निहित तर्क (v
) लेता है (यानी, TypeToValue
जहां पहले प्रकार पैरामीटर में कम Succ[_]
है)। कंपाइलर _0ToInt
(जैसा ऊपर toInt(z)
के मूल्यांकन में किया गया था) की आपूर्ति करता है, और succToInt
मूल्य 1
के साथ एक नया TypeToValue
ऑब्जेक्ट बनाता है। दोबारा, यह ध्यान रखना महत्वपूर्ण है कि संकलक इन सभी मूल्यों को पूरी तरह से प्रदान कर रहा है, क्योंकि हमारे पास स्पष्ट रूप से उन तक पहुंच नहीं है।
अपने काम की जांच कर रहा
है जिसे आपके प्रकार स्तरीय संगणना कर रहे हैं कि आप क्या उम्मीद सत्यापित करने के लिए कई तरीके हैं। यहां कुछ दृष्टिकोण दिए गए हैं। दो प्रकार A
और B
बनाएं, जिन्हें आप सत्यापित करना चाहते हैं बराबर हैं।
Equal[A, B]
implicitly[A =:= B]
वैकल्पिक रूप से, आप एक मूल्य के प्रकार में बदल सकते हैं (जैसा कि ऊपर दिखाया गया है) और मानों की रनटाइम जांच करें। जैसे assert(toInt(a) == toInt(b))
, जहां a
प्रकार A
और b
प्रकार B
है।
अतिरिक्त संसाधन
उपलब्ध निर्माणों का पूरा सेट the scala reference manual (pdf) के प्रकार अनुभाग में पाया जा सकता है।
:
Adriaan Moors स्केला से प्रकार निर्माणकर्ता और उदाहरण के साथ संबंधित विषयों के बारे में कई शैक्षिक पेपर है
Apocalisp एक ब्लॉग है जिसमें टाइप-स्तरीय प्रो के कई उदाहरण हैं स्कैला में gramming।
ScalaZ एक बहुत ही सक्रिय परियोजना है जो विभिन्न प्रकार-स्तर की प्रोग्रामिंग सुविधाओं का उपयोग करके स्कैला एपीआई को विस्तारित करने वाली कार्यक्षमता प्रदान कर रही है। यह एक बहुत ही रोचक परियोजना है जिसका एक बड़ा अनुसरण है।
MetaScala स्कैला के लिए एक प्रकार-स्तरीय लाइब्रेरी है, जिसमें प्राकृतिक संख्याओं, बूलियन, इकाइयों, एचएलआईस्ट आदि के मेटा प्रकार शामिल हैं। यह Jesper Nordenberg (his blog) द्वारा एक परियोजना है।
:
Michid (blog) कुछ कमाल प्रकार स्तरीय प्रोग्रामिंग के स्काला में (अन्य जवाब से) उदाहरण है
Debasish Ghosh (blog) साथ ही कुछ प्रासंगिक पोस्ट है:
(मैं इस विषय पर कुछ शोध कर रहा हूं और यहां मैंने जो सीखा है। मैं अभी भी नया कर रहा हूँ यह करने के लिए है, इसलिए इस सवाल का जवाब किसी भी अशुद्धियों का कहना है कृपया।)
समुदाय विकी? –
व्यक्तिगत रूप से, मुझे लगता है कि कोई भी जो स्कैला में टाइप-स्तरीय प्रोग्रामिंग करना चाहता है, जानता है कि स्कैला में प्रोग्रामिंग को काफी उचित तरीके से कैसे करना है। यहां तक कि यदि इसका मतलब है कि मैं उन लेखों के एक शब्द को समझ नहीं पा रहा हूं जो आपने लिंक किए हैं :-) –