सामना

सामना

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

परिचय

सिलेबस में इस जगह तक पहुँचते-पहुँचते आप फंक्शन की बहुत सी परिभाषाएँ देख चुके हैं। आम तौर पर इन्हें REPL के आउटपुट के बारे में ज़्यादा कुछ बताए बिना ही पेश किया गया था:

julia> f(x) = x^2
f (generic function with 1 method)

तो यह "generic function with 1 method" क्यों लिखा आता है?

मान लीजिए हम आर्गुमेंट के टाइप के बारे में और स्पष्ट होना चाहते हैं।

julia> f(x::Integer) = x^2
f (generic function with 2 methods)

julia> f(x::Real) = x^2
f (generic function with 3 methods)

या हम आर्गुमेंट की संख्या बदल सकते हैं:

julia> f(x, y) = x * y
f (generic function with 4 methods)

लगता है कि एक ही फंक्शन की नई परिभाषाओं को "मेथड" कहा जाता है। पुरानी परिभाषा को मिटाने के बजाय मेथड एक सूची में जोड़े जाते हैं।

हम मेथड की सूची आसानी से देख सकते हैं:

julia> methods(f)  # output edited for brevity
# 4 methods for generic function "f" from Main:
 [1] f(x, y)
 [2] f(x::Integer)
 [3] f(x::Real)
 [4] f(x)

अगर हम फंक्शन f को कॉल करते हैं, तो Julia को किसी तरह पता चल जाता है कि कौन-सा मेथड इस्तेमाल करना है:

julia> f(2.5)  # Float64
6.25

julia> f(2)  # Int64
4

julia> f(2, 3)  # Int64, Int64
6

फंक्शन क्या है?

मैनुअल के मुताबिक, फंक्शन एक ऑब्जेक्ट है जो आर्गुमेंट के एक टपल को एक रिटर्न वैल्यू पर मैप करता है।

f(2, 3) में फंक्शन के आर्गुमेंट को हम आम तौर पर दो अलग-अलग चीज़ें मानते हैं, लेकिन कंपाइलर उन्हें एक ही टपल की तरह देखता है। यह एक ही आर्गुमेंट के लिए भी सच है (हालाँकि इसे साफ़ तौर पर दिखाने के लिए हमें एक कॉमा जोड़ना पड़ता है):

julia> typeof( (2, 3) )
Tuple{Int64, Int64}

julia> typeof( (2,) )
Tuple{Int64}

फंक्शन को एक ब्लैक बॉक्स मानकर हम कह सकते हैं कि अंदर एक टपल जाता है और बाहर एक रिटर्न वैल्यू आती है। अधिक औपचारिक रूप से कहें तो टपल को एक रिटर्न वैल्यू पर मैप किया जाता है।

फंक्शन अलग-अलग संख्या और टाइप के आर्गुमेंट को कैसे संभालते हैं?

इसे आम तौर पर "पॉलिमॉर्फिज़्म" कहा जाता है।

यह कंप्यूटर साइंस में कई दशकों से एक बड़ा विषय रहा है, और इसके लिए अलग-अलग तरीके अपनाए गए हैं। Julia का तरीका अनोखा है, हालाँकि अकेला नहीं।

  • फंक्शन "जेनेरिक" होते हैं, यानी उनसे कई मेथड जुड़े हो सकते हैं।
  • जब तक फंक्शन से मेथड न जुड़ें, फंक्शन सिर्फ नाम भर होते हैं।
  • ज़रूरत के मुताबिक मेथड जोड़े जा सकते हैं, और बहुत बड़ी संख्या में भी (फिलहाल + ऑपरेटर एक फंक्शन है जिसके 161 मेथड हैं)।
  • जब किसी फंक्शन को कॉल किया जाता है, तो Julia कॉल सिग्नेचर देखता है: आर्गुमेंट की संख्या और हर एक का मौजूदा टाइप।
  • कॉल सिग्नेचर से सबसे ज़्यादा मेल खाने वाला मेथड चुना जाता है।
    • आम तौर पर आर्गुमेंट की संख्या बिल्कुल मेल खानी चाहिए (हालाँकि स्प्लैट/स्लर्प ऑपरेटर ... इसे कुछ हद तक बायपास कर सकता है)।
    • जिन मेथड के टाइप कॉल सिग्नेचर से बिल्कुल मेल खाते हैं, उन्हें प्राथमिकता मिलती है।
    • ज़रूरत पड़ने पर Julia कॉल सिग्नेचर के हर आर्गुमेंट के सुपरटाइप देखता है, ताकि सबसे ज़्यादा मेल खाता और सबसे विशिष्ट मेथड मिल जाए।
  • चुने गए मेथड को दिए गए आर्गुमेंट के साथ dispatched किया जाता है, और वह एक परिणाम लौटाता है।
  • अगर कोई उपयुक्त मेथड न मिले, तो एक MethodError उठती है।

ध्यान दीजिए कि Julia डायनैमिकली टाइप्ड है, इसलिए मेथड डिस्पैच रन टाइम पर होता है।

मल्टीपल डिस्पैच: एक उदाहरण

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

ज्यामितीय आकृतियों को दर्शाने के लिए पहले कुछ कस्टम टाइप बनाइए।

julia> abstract type Shape end

julia> struct Circle <: Shape
           radius::Float64
       end

julia> struct Square <: Shape
           side::Float64
       end

julia> struct Rectangle <: Shape
           length::Float64
           width::Float64
       end

इसके बाद हम हर आकृति का क्षेत्रफल निकालने के लिए मेथड बना सकते हैं। हर मेथड एक आर्गुमेंट लेता है, और हर मामले में वह एक अलग कंक्रीट टाइप का होता है, जिसे उपयोगकर्ता ने खुद बनाया है।

julia> area(c::Circle) = π * c.radius^2
area (generic function with 1 method)

julia> area(s::Square) = s.side^2
area (generic function with 2 methods)

julia> area(r::Rectangle) = r.length * r.width
area (generic function with 3 methods)

अब हम कुछ आकृतियाँ बना सकते हैं और उनका क्षेत्रफल निकाल सकते हैं, और हर आकृति के लिए सही फॉर्मूला इस्तेमाल करने का काम Julia के डिस्पैच मेकैनिज़्म पर छोड़ सकते हैं।

julia> circle = Circle(2.3)
Circle(2.3)

julia> area(circle)  # call signature Tuple{Circle}
16.619025137490002

julia> square = Square(1.6)
Square(1.6)

julia> area(square)  # call signature Tuple{Square}
2.5600000000000005

julia> rectangle = Rectangle(1.4, 2.1)
Rectangle(1.4, 2.1)

julia> area(rectangle)  # call signature Tuple{Rectangle}
2.94

पैरामेट्रिक मेथड

मेथड सिग्नेचर डमी टाइप वैल्यू भी ले सकते हैं, लगभग उसी तरह जैसे पैरामेट्रिक टाइप लेते हैं।

इसका सिंटैक्स अलग है, क्योंकि इसमें एक where क्लॉज़ लगाना पड़ता है:

julia> same_type(v::Vector{T}, x::T) where {T} = true
same_type (generic function with 1 method)

julia> same_type([1, 2], 3)
true

julia> same_type([1, 2], "three")
ERROR: MethodError: no method matching same_type(::Vector{Int64}, ::String)

ऊपर के उदाहरण में दोनों आर्गुमेंट का एक ही टाइप T होना चाहिए, चाहे वह कोई भी हो।

T पर एक प्रतिबंध लगाकर हम इसे और स्पष्ट कर सकते हैं:

julia> same_type(v::Vector{T}, x::T) where {T<:Number} = true
same_type (generic function with 2 methods)

इस मेथड के साथ सिर्फ एक जैसे संख्यात्मक टाइप ही true लौटाते हैं।

एक से ज़्यादा डमी वेरिएबल भी हो सकते हैं, जिन्हें where क्लॉज़ में कॉमा से अलग किया जाता है।

julia> myfunc(a::S, b::T) where {S, T} = true
myfunc (generic function with 1 method)

निष्कर्ष

मल्टीपल डिस्पैच बहुत लचीला है और Julia में बहुत अच्छा प्रदर्शन देता है, इसलिए इसका इस्तेमाल बहुत व्यापक रूप से होता है।

जैसा कि + के 161 मेथड का उदाहरण बताता है, Julia प्रोग्रामर कोशिश करते हैं कि मेथड ऐसे टाइप के साथ बनाएँ जो बहुत सटीक ढंग से तय किए गए हों। बाइटकोड के स्तर पर दो पूर्णांक जोड़ना और दो दशमलव संख्याएँ जोड़ना बहुत अलग बात है, और एक पूर्णांक को एक दशमलव संख्या में जोड़ने पर टाइप प्रोमोशन की एक और उलझन जुड़ जाती है।

टाइप जितना ज़्यादा विशिष्ट होगा, कंपाइलर उतना ही ज़्यादा ऑप्टिमाइज़ेशन कर सकता है: Exercism के एक छोटे-से अभ्यास में इसका महत्व मामूली है, लेकिन जिन बड़े संख्यात्मक सिमुलेशनों के लिए Julia को बनाया गया है, उनमें प्रदर्शन के लिए यह बहुत ज़रूरी है।

अगर आप जानते हैं कि किसी मेथड को कौन-से इनपुट मिलेंगे, तो कंपाइलर को ज़रूर बताइए!

निर्देश

इस अभ्यास में आप एक ऐसा सिमुलेशन बनाएँगे जिसमें जीवों का आपस में सामना होता है। इससे आप Julia के मुख्य पैराडाइम, मल्टिपल डिस्पैच, की बुनियादी बातों से परिचित होंगे।

For this exercise, all function definitions should be a single-line declaration with no if/else logic.

आम तौर पर सामनों में एक इकाई a का दूसरी इकाई b से मिलना और उस पर प्रतिक्रिया देना शामिल होता है।

encounter(a, b) = "$(name(a)) meets $(name(b)) and $(meets(a, b))."

सबसे पहले हम यह सिमुलेशन बनाएँगे कि जब बिल्लियाँ और कुत्ते मिलते हैं, तो क्या होता है।

1. कस्टम टाइप बनाइए

सबसे पहले एक एब्सट्रैक्ट टाइप Pet जोड़िए।

फिर Cat और Dog टाइप को Pet का सबटाइप बनाइए। इन दोनों में सिर्फ़ एक फील्ड होती है, जिसका नाम name है।

2. पालतू जानवर का नाम निकालिए

एक फंक्शन name() बनाइए जो किसी पालतू जानवर का नाम लौटाता है।

julia> fido = Dog("Fido")
Dog("Fido")

julia> name(fido)
"Fido"

3. तय कीजिए कि बिल्लियों और कुत्तों के मिलने पर क्या होता है

नीचे दिए गए सामनों के लिए meets() मेथड बनाइए:

  • जब दो कुत्ते मिलते हैं, तो उनकी प्रतिक्रिया sniff होती है।
  • जब बिल्ली कुत्ते से मिलती है, तो उसकी प्रतिक्रिया hisses होती है।
  • जब कुत्ता बिल्ली से मिलता है, तो उसकी प्रतिक्रिया chases होती है।
  • जब दो बिल्लियाँ मिलती हैं, तो उनकी प्रतिक्रिया slink होती है।
julia> ginger = Cat("Ginger")
Cat("Ginger")

julia> meets(ginger, fido)
"hisses"

4. दो इकाइयों के बीच सामना तय कीजिए

एक ही मेथड वाला encounter() फंक्शन बनाइए, जो बताए कि जब दो नाम वाली इकाइयाँ मिलती हैं, तो क्या होता है।

julia> encounter(ginger, fido)
"Ginger meets Fido and hisses."

5. पालतू जानवरों के बीच होने वाले सामनों के लिए एक फॉलबैक प्रतिक्रिया तय कीजिए

अगर टहलते समय उन्हें कोई और पालतू जानवर मिल जाए, जैसे कोई घोड़ा, तो क्या होता है?

  • अगर किसी पालतू जानवर को कोई ऐसा पालतू जानवर मिल जाए जिसे वह नहीं पहचानता, तो उसकी प्रतिक्रिया is cautious होती है।
julia> bella = Horse("Bella")
Horse("Bella")

julia> encounter(fido, bella)
"Fido meets Bella and is cautious."

6. अगर किसी पालतू जानवर को कोई अनजानी चीज़ मिल जाए, तो एक फॉलबैक तय कीजिए

पालतू जानवरों को ऐसी बहुत सी और चीज़ें भी मिल सकती हैं जो पालतू नहीं हैं: कारें, मनुष्य, पौधे, प्राकृतिक आपदाएँ, क्षुद्रग्रह… तब क्या होता है?

  • अगर किसी पालतू जानवर को ऐसी कोई चीज़ मिल जाए जिसे उसने पहले कभी नहीं देखा, तो उसकी प्रतिक्रिया runs away होती है।
julia> colnago = Bicycle("Colnago")
Bicycle("Colnago")

julia> encounter(ginger, colnago)
"Ginger meets Colnago and runs away."

7. एक जेनेरिक फॉलबैक तय कीजिए

हमारे सिमुलेशन में और भी बहुत से सामने हो सकते हैं। एक कार कुत्ते से मिल सकती है, दो इलेक्ट्रॉन आपस में मिलकर एक-दूसरे पर असर डाल सकते हैं…

सारे सामनों को पहले से तय करना असंभव है, इसलिए हम एक जेनेरिक फॉलबैक बनाएँगे।

  • अगर दो अनजान चीज़ों या जीवों का आपस में सामना होता है, तो प्रतिक्रिया nothing happens होती है।
julia> γ1 = Photon("γ1")
Photon("γ1")

julia> γ2 = Photon("γ2")
Photon("γ2")

julia> encounter(γ1, γ2)
"γ1 meets γ2 and nothing happens." 
# This is true, photons just pass through each other.
GitHub के ज़रिए संपादित करें यह लिंक एक नई विंडो या टैब में खुलता है
Julia Exercism

सामना शुरू करने के लिए तैयार हैं?

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