ट्रैक
/
Julia
Julia
/
अभ्यास
/
ग्रेडिंग गुरु
ग्रेडिंग गुरु

ग्रेडिंग गुरु

सीखने का अभ्यास

परिचय

अब तक सिलेबस ने टाइप के बारे में ज़्यादा कुछ नहीं कहा है, लेकिन साफ है कि Julia में ये मौजूद हैं:

julia> vals = (42, 4.3, π, "hello", 'Q')
(42, 4.3, π, "hello", 'Q')
julia> typeof(vals)
Tuple{Int64, Float64, Irrational{:π}, String, Char}

हमने टाइप कभी निर्दिष्ट नहीं किए, फिर भी Julia ने उन्हें असाइन कर दिया।

  1. Julia में types हैं, जो इसके डिज़ाइन के केंद्र में हैं।
  2. Julia आमतौर पर Type Inference का उपयोग करके टाइप का "अनुमान" लगा सकती है।

JIT कंपाइलर (सारे) कोड को देखता है, यह देखता है कि किसी वेरिएबल का उपयोग कैसे हो रहा है, और उस उपयोग के अनुरूप एक उपयुक्त डिफॉल्ट टाइप का अनुमान लगाता है।

टाइप असाइनमेंट

आसान ट्यूटोरियल अभ्यास हल करने के लिए टाइप इनफेरेंस पर भरोसा करना ठीक है, लेकिन बड़े प्रोग्राम के लिए आपको ज़्यादा सटीक नियंत्रण की ज़रूरत पड़ सकती है।

ज़्यादातर आधुनिक प्रोसेसर पर एक पूर्णांक का डिफॉल्ट Int64 होता है। हमने Numbers कॉन्सेप्ट में देखा था कि किसी वैल्यू को किसी खास गैर-डिफॉल्ट टाइप में बदला जा सकता है।

julia> x = Int16(42)
42
julia> typeof(x)
Int16

लेकिन वेरिएबल x को किसी दूसरे टाइप की वैल्यू फिर भी असाइन की जा सकती है:

julia> x = "changed"
"changed"
julia> typeof(x)
String

यह type instability है, और इसका मतलब है:

  • छोटी स्क्रिप्ट में यह बहुत सुविधाजनक होती है।
  • बड़े प्रोग्राम में यह परफ़ॉर्मेंस और भरोसे के लिए नुकसानदेह होती है।

इसके बजाय, हम :: ऑपरेटर का उपयोग करके x का टाइप तय कर सकते हैं:

julia> y::Int16 = 42
42
julia> typeof(y)
Int16
julia> y = "changed"
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int16
The function `convert` exists, but no method is defined for this combination of argument types.

अब y का टाइप Int16 है, और हमेशा रहेगा। इसलिए कंपाइलर को पता होता है कि इसके लिए कितने बाइट आरक्षित करने हैं, और वह बाकी कोड को इस तरह ऑप्टिमाइज़ कर सकता है कि वह एक स्थिर टाइप पर भरोसा करे। इस मायने में यह वेरिएबल C जैसी स्टैटिकली-टाइप्ड भाषा के वेरिएबलो जैसा ही है।

टाइप का पदानुक्रम

Int64, Int16, String, Char: ये टाइप "कहाँ से आते हैं"?

कई ऑब्जेक्ट-ओरिएंटेड (OO) भाषाओं में हर टाइप एक क्लास होता है, सबक्लासिंग उन्हें एक क्लास पदानुक्रम में सजाती है, और क्लास मेथड उनका व्यवहार तय करते हैं।

Java और Ruby इस पैटर्न के साफ उदाहरण हैं, लेकिन अंदरूनी रूप से Python भी ऐसी ही है।

Julia में क्लास नहीं होती।

दस्तावेज़ों में दिया गया कारण यह है कि OO फीचर JIT कंपाइलर में रुकावट डालते हैं और रनटाइम परफ़ॉर्मेंस को नुकसान पहुँचाते हैं।

फिर भी, इस कोड को देखिए:

julia> y::Int16 = 42
42
julia> typeof(y)
Int16
julia> supertype(Int16)
Signed
julia> supertypes(Int16)
(Int16, Signed, Integer, Real, Number, Any)

कुछ बातें स्पष्ट कर लेते हैं:

  • Int16 एक टाइप है, और हम इस टाइप के वेरिएबल बना सकते हैं।
  • Int16, Signed का सबटाइप है, और supertype() फंक्शन हमें यह दिखाता है।
  • टाइपो का एक पदानुक्रम है, जो Integer, Real और Number से होते हुए सबसे ऊपर Any तक जाता है, और subtypes() हमें पदानुक्रम की यह शाखा दिखा देगा।

सारी शाखाएँ Any पर जाकर खत्म होती हैं, और Any इस मायने में अनोखा है कि वह खुद अपना ही सुपरटाइप है।

julia> supertypes(String)
(String, AbstractString, Any)
julia> supertype(Any)
Any

तो Julia में class का पदानुक्रम नहीं है, लेकिन type का पदानुक्रम ज़रूर है।

आगे चलकर हम यह समझने की कोशिश करेंगे कि यह काम कैसे करता है, लेकिन पहले अभी बहुत कुछ खोजना बाकी है।

टाइप की जाँच

हम सामान्य तरीके से बराबरी की जाँच के लिए typeof() का उपयोग कर सकते हैं।

julia> typeof(11)
Int64
julia> typeof(11) == Int64
true
julia> typeof(11) == Number
false

टाइप की बराबरी बिल्कुल सटीक होनी चाहिए, क्योंकि तुलना के इस तरीके को टाइप पदानुक्रम की कोई समझ नहीं होती।

इससे ज़्यादा लचीले ढंग से, isa हमें बताता है कि किसी वैल्यू का टाइप तुलना करने वाले टाइप जैसा ही है या उसका कोई सबटाइप है। इसका उपयोग फंक्शन रूप में या इनफ़िक्स रूप में, दोनों तरह से किया जा सकता है।

julia> 12 isa Int64
true
julia> 12 isa Number
true
julia> isa(12, Number)
true
julia> 12 isa String
false

ध्यान दीजिए कि isa बाईं ओर एक value की अपेक्षा करता है, type की नहीं।

इस तरह दो टाइपो की तुलना करने पर अनपेक्षित परिणाम मिलेंगे। सही ऑपरेटर <: है, जिसे हम आगे के कॉन्सेप्ट में और भी बहुत बार देखेंगे।

julia> Int64 isa Number  ## Don't do this!
false
julia> Int64 <: Number
true

एब्स्ट्रैक्ट बनाम कॉन्क्रीट टाइप

हमने देखा कि टाइप पदानुक्रम एक पेड़ जैसी संरचना बनाता है (CS के अर्थ में, जिसकी जड़ सबसे ऊपर होती है)।

पेड़ में हर चीज़ एक node होती है, और इन्हें वर्गों में बाँटा जा सकता है:

  1. जिन node के सबटाइप होते हैं, उन्हें abstract कहा जाता है।
  2. बिना सबटाइप वाले पत्ती जैसे node को concrete कहा जाता है।
julia> subtypes(Integer)  # an abstract type
3-element Vector{Any}:
 Bool
 Signed
 Unsigned
julia> subtypes(Int64)  # a concrete type
Type[]

यह एक महत्वपूर्ण अंतर है, क्योंकि सिर्फ कॉन्क्रीट टाइप को ही वेरिएबल के रूप में instantiated किया जा सकता है।

julia> a::Int16 = 42
42
julia> typeof(a)
Int16
julia> b::Integer = 42
42
julia> typeof(b)
Int64

ध्यान दीजिए कि एब्स्ट्रैक्ट टाइप इस्तेमाल करने पर (इस मामले में) कोई एरर संदेश नहीं मिलता, लेकिन कंपाइलर एक उपयुक्त कॉन्क्रीट टाइप बना देता है: Integer की जगह Int64।

निर्देश

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

ग्रेडिंग स्केल आम तौर पर 0-10 तक होता है, इसलिए हर ग्रेड के लिए केवल आठ बिट वाला डेटा टाइप इस्तेमाल करना सबसे कुशल है।

  • कुछ प्रोफेसर वास्तविक संख्याएँ इस्तेमाल करते हैं (क्योंकि वे सटीकता को लेकर बहुत सख्त हैं), और आपको इन्हें UInt8 डेटा टाइप में बदलना होगा।
  • कुछ अन्य प्रोफेसर ऋणात्मक संख्याओं वाले पूर्णांक इस्तेमाल करते हैं (खास तौर पर बहुत उपद्रवी विद्यार्थियों को सज़ा देने के लिए), और ऐसी स्थितियों में आपको इन्हें Int8 डेटा टाइप में बदलना होगा।

अंकों को बदलने वाला फंक्शन बनाने के बाद आपको एक और फंक्शन लिखना होगा, जो उन संग्रहों को संभालेगा जिनमें अंक रखे गए हैं। यह फंक्शन अंकों को डिमोट करेगा और उन्हें अवरोही क्रम में लौटाएगा।

  • कुछ प्रोफेसर अपने अंकों को आरोही क्रम में क्रमबद्ध Vector में रखते हैं, क्योंकि वे अपने डेटा के बारे में बहुत चौकस रहते हैं।
  • कुछ अन्य प्रोफेसर अपने अंकों को Set में रखते हैं, जो क्रमबद्ध नहीं होते, क्योंकि वे थोड़े आलसी हैं।

दोनों फंक्शनों में अमान्य इनपुट मिलने पर आपको एक MethodError फेंकना होगा।

Note

एक्सेप्शन हैंडलिंग को आगे के किसी कॉन्सेप्ट में समझाया जाएगा, इसलिए इस अभ्यास के लिए आप नीचे दिया गया सिंटैक्स इस्तेमाल कर सकते हैं:

throw(MethodError(f, args))

यहाँ f फंक्शन है और args उन आर्गुमेंट का टपल है जो फंक्शन को दिए जाते हैं। demote(n) फंक्शन में f यानी demote है और args यानी (n,) है:

throw(MethodError(demote, (n,)))

1. अंकों को डिमोट कीजिए

demote(n) मेथड बनाइए।

  • Float64 इनपुट मिलने पर यह निकटतम पूर्ण संख्या तक ऊपर की ओर राउंड करे और UInt8 डेटा टाइप लौटाए।
  • किसी भी Integer के साथ यह उसी पूर्णांक को Int8 डेटा टाइप में लौटाए।
  • बाकी सभी इनपुट एक MethodError फेंकें।
julia> demote(4.2)::UInt8
5

julia> demote(4)::Int8
4

julia> demote("hi")
MethodError: no method matching demote(::String)     #output truncated

2. डेटा को प्रीप्रोसेस कीजिए

preprocess(coll) मेथड बनाइए।

  • Vector इनपुट मिलने पर यह सभी संख्याओं को डिमोट करे और वेक्टर को उलट दे।
  • Set इनपुट मिलने पर यह सभी संख्याओं को डिमोट करे और अवरोही क्रम में क्रमबद्ध वेक्टर लौटाए।
  • बाकी सभी इनपुट एक MethodError फेंकें।
julia> preprocess([1, 2, 3])
3-element Vector{Int8}:
 3
 2
 1

julia> preprocess(Set([2.2, 5.8, 3.4]))
3-element Vector{UInt8}:
 6
 4
 3

julia> preprocess(42)
MethodError: no method matching preprocess(::Int64)     #output truncated
GitHub के ज़रिए संपादित करें यह लिंक एक नई विंडो या टैब में खुलता है
Julia Exercism

ग्रेडिंग गुरु शुरू करने के लिए तैयार हैं?

Exercism पर साइन अप कीजिए और Julia को 35 कॉन्सेप्ट128 अभ्यास तथा असली इंसानों से मिलने वाली मेंटरिंग के साथ सीखिए और उसमें महारत हासिल कीजिए, वह भी बिल्कुल मुफ्त।