Type system notation को कैसे पढ़ें?
(langdev.stackexchange.com)- type system notation अलग-अलग स्रोतों में भले अलग दिखे, लेकिन अगर grammar, typing relation, और inference rules का साझा ढांचा समझ लिया जाए, तो ज़्यादातर रूपांतरों को समझा जा सकता है
- type system भाषा के abstract syntax पर काम करता है, इसलिए पहले type रखने वाले term और type स्वयं को grammar में अलग करना ज़रूरी है
⊢ e: τएक typing judgment है, जिसका अर्थ है “expressioneका typeτहै”, और इसे ऐसे inference rule की तरह पढ़ा जाता है जहाँ क्षैतिज रेखा के ऊपर की सभी शर्तें सही हों तो नीचे का निष्कर्ष भी सही होता है- जब variables और functions आते हैं, तो
Γ ⊢ e: τकी तरह एक context जुड़ जाता है जो मौजूदा scope में variable names और types को track करता है - कई typing rules को recursive type-checking function की तरह पढ़ा जा सकता है, लेकिन हर logical judgment सीधे निर्णययोग्य type-checking algorithm नहीं बन जाता
grammar से शुरू होने वाली type system notation
- type system एक programming language का syntactic system है, यानी यह भाषा के abstract syntax पर काम करने वाले rules का एक सेट है
- type system का व्यापक विवरण आम तौर पर पहले उस syntax structure को grammar के रूप में देता है, और फिर उसे BNF notation में लिखता है
- सबसे सरल type language में भी syntax मोटे तौर पर दो श्रेणियों में बँटा होता है
e: type रखने वाले expressionτ: expressions पर लगने वाले type
- उदाहरण भाषा में boolean literals, integer literals, conditional expressions, arithmetic operations, और comparison operations expressions के रूप में होते हैं, और
BoolतथाInttypes के रूप में इस्तेमाल होते हैं - type symbols अलग-अलग स्रोतों में
τकी जगहt,T,σ, या दूसरे lowercase Greek letters से भी लिखे जा सकते हैं, लेकिन कुल structure लगभग वही रहता है - ज़्यादा जटिल भाषाओं में statements, pattern matching patterns जैसी और भी syntax categories शामिल हो सकती हैं
typing relation और judgment को पढ़ना
- grammar तय करने के बाद आम तौर पर
e : τके रूप में typing relation परिभाषित की जाती है1 + 2 : Intका मतलब है “1 + 2का typeIntहै”1 + 2 : Boolका मतलब होगा कि वही expressionBooltype का है, जो सही नहीं हैtrue + 2 : Intमें expression ही अर्थपूर्ण नहीं है, इसलिए उसका कोई type नहीं बनता
⊢ e : τएक typing judgment है, और⊢को “इसके बाद का कथन सत्य है” की तरह पढ़ा जा सकता है- जिन rules में क्षैतिज रेखा के ऊपर कुछ नहीं होता, वे हमेशा सत्य रहने वाले axioms होते हैं
⊢ true : Bool⊢ false : Bool- integer literals के rules जैसे
⊢ 0 : Int,⊢ 1 : Int,⊢ -1 : Int
- जिन rules में ऊपर और नीचे दोनों हिस्से होते हैं, वे inference rules होते हैं
- अगर ऊपर की सभी शर्तें सत्य हैं, तो नीचे का निष्कर्ष सत्य है
- अगर
e₁औरe₂दोनोंIntहैं, तोe₁ + e₂का typeIntहै - अगर
e₁औरe₂दोनोंIntहैं, तोe₁ < e₂का typeBoolहै
conditional expressions और type variables
if ... then ... else ...की दोनों branches किसी भी type की हो सकती हैं, लेकिन दोनों का type एक जैसा होना चाहिएif true then 1 else 2मान्य हैif true then false else trueमान्य हैif true then 1 else trueमान्य नहीं है
- इसे व्यक्त करने के लिए rule branch type दिखाने वाले variable
τका उपयोग करता है- condition expression
e₁का typeBoolहोना चाहिए thenbranche₂औरelsebranche₃दोनों का type वहीτहोना चाहिए- पूरे conditional expression का type भी
τही होगा
- condition expression
- rule लागू करते समय
τके लिए कोई भी type चुना जा सकता है, लेकिन उसी rule के अंदर उस चुनाव को एकसमान रखना पड़ता है
inference rules को algorithm की तरह पढ़ना
- यह notation formal logic से आया है, और type system specification का तरीका खास तौर पर natural deduction से मिलता-जुलता है
- ऐसे rules का उपयोग system properties के formal proofs बनाने में होता है, और type safety जैसी विशेषताओं को साबित करने में यह महत्वपूर्ण हैं
- हर logical judgment सीधे किसी निर्णययोग्य type-checking algorithm के बराबर नहीं होता
- कई मामलों में
⊢ e : τको ऐसे function की तरह पढ़ा जा सकता है जो expressioneसे typeτनिकालता है- grammar में expression के हर form के लिए आम तौर पर एक rule होता है
- हर typing rule को recursive type-checking function की एक branch की तरह देखा जा सकता है
- उदाहरण का
inferfunction इस flow से मेल खाता हैtrueयाfalseका typeBoolहै- integer literals का type
Intहै e₁ + e₂के लिए पहले देखा जाता है कि दोनों तरफ inference resultIntहै या नहीं, फिरIntलौटाया जाता हैe₁ < e₂के लिए पहले जाँचा जाता है कि दोनोंIntहैं या नहीं, फिरBoolलौटाया जाता हैif e₁ then e₂ else e₃में पहले condition केBoolहोने की जाँच होती है, फिर दोनों branches के type एक जैसे हैं या नहीं, और उसके बाद वही type लौटाया जाता है
- भले इसे सीधे algorithm में न बदला जा सके, judgment में
eको input औरτको output की तरह सोचना information flow समझने में मदद करता है
variables और context
- उपयोगी programming languages को संभालने के लिए variables चाहिए होते हैं, और उदाहरण में functions जोड़कर इसे simply typed lambda calculus के रूप में बढ़ाया जाता है
- विस्तारित grammar में ये शामिल होते हैं
- variable
x - function abstraction
λx:τ. e - function application
e e - function type
τ → τ
- variable
λx:τ. eTypeScript के(x:τ) => eके बराबर है, औरf xका संबंधf(x)से है- variable का type उस context पर निर्भर करता है जहाँ वह आता है, इसलिए सिर्फ
⊢ x : ???के रूप में rule नहीं लिखा जा सकता - इसलिए typing judgment को बढ़ाकर
Γ ⊢ e : τकिया जाता हैΓcontext या type environment है⊢बाईं तरफ की context assumptions और दाईं तरफ साबित किए जाने वाले कथन को अलग करता है- इसे “context
Γके तहत expressioneका typeτहै” की तरह पढ़ा जाता है
- algorithmic नज़रिए से
ΓकोMap<Variable, Type>जैसे अतिरिक्त input की तरह देखा जा सकता है - formal रूप में context को भी syntax structure के रूप में लिखा जाता है
∅: empty contextΓ, x:τ: variable binding जोड़ने वाला context- कभी-कभी
∅की जगह•को empty context के रूप में लिखा जाता है
- इस notation में context, variable names को types से map करने वाली association list के काफ़ी करीब होता है
rules के अंदर context क्या करता है
- कई typing rules context को बदले बिना वैसे का वैसा आगे बढ़ा देते हैं
Γ ⊢ true : Bool- अगर
Γ ⊢ e₁ : IntऔरΓ ⊢ e₂ : Intहै, तोΓ ⊢ e₁ + e₂ : Int
- variable use और lambda expression के rules में context की केंद्रीय भूमिका होती है
- अगर
x:τ ∈ Γहै, तोΓ ⊢ x : τ - अगर
Γ, x:τ₁ ⊢ e : τ₂है, तोΓ ⊢ (λx:τ₁. e) : τ₁ → τ₂
- अगर
- lambda expression के body
eकी type checking करते समय context को नई bindingx:τ₁से बढ़ाया जाता है - variable rule कहता है कि अगर मौजूदा context में variable binding मौजूद है, तो उस variable का वही type माना जाएगा
- context, lambda rule और variable rule के बीच जानकारी पहुँचाने वाले communication mechanism की तरह काम करता है
- सरलता के लिए, इस तरह की type system specification आम तौर पर मानती है कि सभी variables पहले से resolve होकर unique बनाए जा चुके हैं, और variable shadowing को नहीं संभालती
- function application rule function expression और argument expression दोनों के types को साथ में जाँचता है
e₁का typeτ₁ → τ₂होना चाहिएe₂का typeτ₁होना चाहिए- पूरे application
e₁ e₂का typeτ₂होगा
अक्सर दिखने वाली अतिरिक्त notation
- inference rules हमेशा केवल vertical form में ही नहीं लिखे जाते
- कई शर्तें horizontal रूप में साथ-साथ रखी जा सकती हैं
- vertical layout और horizontal layout एक ही rule में मिश्रित भी हो सकते हैं
- क्षैतिज रेखा के ऊपर की शर्तें आम तौर पर दूसरे judgments होती हैं, लेकिन कोई मनमानी boolean condition, यानी side condition, भी आ सकती है
- variable rule में
x:τ ∈ Γइसका उदाहरण है - algorithmic type systems में
α freshलिखा जा सकता है, जिसका मतलब है किαएक नया type variable होना चाहिए जो दूसरे type variables से अलग हो
- variable rule में
subtyping
- subtyping types के बीच compatibility को strict equality से थोड़ा ढीले रूप में देखने वाला संबंध है, और इसे स्पष्ट रूप से परिभाषित करना पड़ता है
- इसे आम तौर पर
τ₁ <: τ₂लिखा जाता है, और पढ़ा जाता है “τ₁,τ₂का subtype है” - एक सरल subtyping relation top type
⊤और bottom type⊥को शामिल कर सकती हैτ <: τ: हर type, अपने ही type का subtype हैτ <: ⊤: हर type,⊤का subtype है⊥ <: τ:⊥हर type का subtype है
- पहला rule reflexivity rule है, जिसे अक्सर संक्षेप में
reflकहा जाता है - subtyping की अनुमति देनी हो, तो जिन typing rules में इसकी ज़रूरत है वहाँ इस relation का उपयोग स्पष्ट रूप से दिखाना पड़ता है
- जैसे function application rule में, अगर argument type
τ₁, parameter typeτ₂का subtype है, तो application की अनुमति दी जा सकती है
- जैसे function application rule में, अगर argument type
multiple contexts और bidirectional type checking
- कुछ type systems ऐसे typing judgments परिभाषित करते हैं जिनमें एक से ज़्यादा contexts होते हैं
- दूसरे context को आम तौर पर
Δकहा जाता है Γ;Δ ⊢ e : τअक्सर तब इस्तेमाल होता है जब दोनों contexts input की तरह काम कर रहे होंΓ ⊢ e : τ ⊣ Δअक्सर तब लिखा जाता है जबΔoutput की तरह काम कर रहा हो
- दूसरे context को आम तौर पर
- दूसरे context का उपयोग उसके उद्देश्य के अनुसार बदलता है
- इसका उपयोग यह सीमित करने के लिए हो सकता है कि कुछ variables को केवल किसी खास expression के अंदर ही refer किया जा सके
- resource-aware programming languages में यह output context के रूप में track कर सकता है कि कौन-से variables consume हो चुके हैं
- bidirectional type checking ऐसा तरीका है जो constraint solver के बिना सीमित non-local type inference करता है
- bidirectional system सामान्य
Γ ⊢ e : τjudgment को दो विशेष judgments में बाँट देता हैΓ ⊢ e ⇐ τ: यह checking judgment है, जो जाँचता है कि expressioneका expected typeτहै या नहीं; algorithmic रूप सेτinput हैΓ ⊢ e ⇒ τ: यह inference judgment है, जो तब इस्तेमाल होता है जब expected type की जानकारी न हो; algorithmic रूप सेτoutput है
- दोनों judgments को परस्पर recursive तरीके से परिभाषित किया जाता है ताकि type information दोनों दिशाओं में प्रवाहित हो सके
- इस तरीके में कुछ type annotations छोड़े जा सकते हैं, और lambda abstraction के checking rule में expected function type से parameter type मिल जाने के कारण variable binder पर annotation छोड़ा जा सकता है
1 टिप्पणियां
Hacker News की रायें
Guy Steele ने पहले इस विषय पर एक talk दी थी। कुछ notations को उन्होंने खोजे जा सकने वाले नाम भी दिए थे, जैसे दो-आयामी inference-rule diagrams
वे इसे computer science metanotation कहते हैं, लेकिन निजी तौर पर यह programming language theory के ज़्यादा करीब लगता है। https://m.youtube.com/watch?v=dCuZkaaou0Q
https://en.wikipedia.org/wiki/Guy_Steele Guy Steele
https://www.codemesh.io/codemesh2017/guy-l-steele Code Mesh 2017 में "A Cobbler's Child" talk
https://www.youtube.com/watch?v=qNPlDnX6Mio "A Cobbler's Child" (YouTube पर video)
https://www.youtube.com/watch?v=dCuZkaaou0Q "It's Time for a New Old Language" (YouTube पर video)
https://news.ycombinator.com/item?id=15473199 HN पर discussion
https://labs.oracle.com/pls/apex/f?p=94065:40150:0::::P40150... Slides
अजीब है कि इंसानी कला-कौशल की सबसे सटीक चीज़ों को सबसे सटीक तरीके से बताने वाले लोग अस्पष्ट और असंगत notation इस्तेमाल कर रहे हैं
यह notation Frege तक जाती है। अगर पता न हो कि क्या खोजना है, तो इसे खोज पाना मुश्किल है, लेकिन यह लेख काफ़ी अच्छा summary लगता है: https://plato.stanford.edu/entries/frege-logic
turnstile symbol
|-पहले से इस्तेमाल में था, और class में “Fregescher Schlussstrich”, यानी Frege की conclusion stroke कही जाने वाली horizontal line, मूल रूप से turnstile का ही हिस्सा थी और लगता है आधुनिक notation में अलग element बन गईBenjamin C. Pierce की Types and Programming Languages इस तरह की चीज़ों को cover करने वाली अच्छी textbook है
computer science major होने के बावजूद
|–और|=के meaning का difference, और इस्तेमाल हुए variables किस meta-syntax level पर हैं, यह अब भी उलझाता हैirony यह है कि इसकी एक वजह यह है कि notation में खुद explicit types नहीं हैं
जो लोग पढ़ने को लेकर हिचक रहे हैं: यह लेख computer science papers में आने वाली type system notation की explanation है, और असल में type systems के लिए BNF notation, inference rules वगैरह का primer है
अच्छा summary लगता है
type application का logical concept समझता हूं, लेकिन computer science papers अक्सर नहीं पढ़ता, इसलिए symbols और meanings का mapping दिमाग में ठीक से बैठता नहीं
examples में
𝗍𝗋𝗎𝖾+2:𝖨𝗇𝗍का मतलब “𝗍𝗋𝗎𝖾+2का type𝖨𝗇𝗍है” बताया गया है, लेकिन फिर कहा गया है कि expression𝗍𝗋𝗎𝖾+2खुद ही nonsensical है और इसका कोई type नहीं, इसलिए यह और अजीब हैलेकिन Python में
True + 2सच में integer है और उसका value 3 है। ऐसा होना चाहिए या नहीं, यह अलग बात है; असल में ऐसा हैTrue + 2समझ में आता है, तो बस ऐसा allow करने वाला judgment rule खुद define कर दीजिएlogic और type system theory को इस बात से फर्क नहीं पड़ता कि आप कौन-से axioms और inference rules इस्तेमाल करते हैं; वे बस आपको उन rules और उनके interactions के बारे में infer करने देते हैं। उदाहरण के लिए
|- True : Bool,|- True : Intरख सकते हैं, या अगर सिर्फ specific expressions में allow करना हो तो|- x : Intसे|- True + x: Intderive करने जैसा बना सकते हैंtrue1 पर map होता है, इसलिएtrue+1=2हो जाता हैTrue + 2error न भी दे, तब भी programmers को थोड़ा syntactic sugar देने के लिए language semantics को infer करना मुश्किल बना देता है, इसलिए यह अब भी मूर्खतापूर्ण हैअच्छा है। कई सालों से जिज्ञासा थी, लेकिन और जानने के लिए कौन-से search terms डालूं, पता नहीं था
कभी-कभी जब कोई मेहनत से सीखी हुई गुप्त विद्या मुफ्त में खोल देता है, तो बेवजह बुरा लगता है ;) जब मैं यह सीख रहा था, तब ऐसा लेख होता तो सच में अच्छा होता। उम्मीद है accessibility बढ़े तो गड़बड़ languages कम हों
Ada Reference Manual पढ़ते समय इस तरह के syntax को तुरंत पहचान लिया था। नाम नहीं जानता था, लेकिन असली use case में देखकर दिलचस्प लगा, और पूरी language उसी notation से define की गई है
उदाहरण: https://ada-lang.io/docs/arm/AA-3/AA-3.7#syntax
Ada Reference Manual अपने इस्तेमाल किए गए notation को स्पष्ट करता है। यह Backus-Naur Form का एक variant इस्तेमाल करता है, और link किए गए section में उस खास variant को समझाया गया है
लगता है यह उस एक मुद्दे का प्रचार करने के लिए अच्छी जगह है जिस पर मैं अंत तक अड़ा रहने वाला हूँ। colon का इस्तेमाल करने वाले type annotation format में colon के दोनों तरफ spacing समान होनी चाहिए
मेरे हिसाब से ये संयोग से एक जैसे दिखने वाले—यानी दो dots से बने—दो अलग-अलग symbols हैं। एक label colon है, जैसे English में आगे वाला हिस्सा पीछे वाले को introduce करता है या left side right side का label होता है; Python में block शुरू करना, key-value pair, C या Rust में struct name-value pair इसी में आते हैं
दूसरा mathematics से लिया गया type annotation है। यह एक binary relation है, और binary relation में left-right spacing समान रखी जाती है। जैसे हम
x= 1,x> y,x+ zनहीं लिखते, वैसे हीx: Xनहीं बल्किx : Xलिखना natural लगता हैa: bदेखते ही यह तुरंत label colon की तरह पढ़ा जाता है, और अगर वह type annotation हो तो हर बार बहुत छोटा-सा अतिरिक्त mental transformation चाहिए होता है। यह programming language syntax की बात है, और निजी तौर पर मुझेX xकी तुलना मेंx : Xकहीं ज्यादा पसंद है[1] “Evangelion” εὐαγγέλιον से आया एक शानदार शब्द है, यानी अच्छी खबर। [2] https://en.wikipedia.org/wiki/Colon_(punctuation)#Usage_in_E...
f: X->Yजैसी notation सच में मिलती है, जिसमें colon के right में ज्यादा space होता है, और मैंने जिन 3 किताबों को देखा उनमें से 1 ने सिर्फ वही notation इस्तेमाल की थीसाथ ही वह भी अभी तक labeling के करीब ही है, यानी किसी खास तरह के map को label करना। mathematics में colon सचमुच अलग अर्थ में तब इस्तेमाल होता है जब वह
such thatका abbreviation होता है; जैसे{ x : x \in IN and x | 2}जैसे set definition में या quantifier के साथ यह अक्सर आता हैX xnotation पढ़ते समय महसूस होती है।x: Xमुझे कहीं ज्यादा natural लगता है, और natural language में colon इस्तेमाल करने के तरीके के भी करीब लगता हैकोई proposition होता है और colon के बाद वाला हिस्सा उसे ज्यादा detail में समझाता है; type भी left में मौजूद चीज के बारे में अतिरिक्त जानकारी है, इस लिहाज से यह बिल्कुल फिट बैठता है
t[space]:[space]Tकी तरह colon के दोनों तरफ समान space रखना standard practice माना जाता हैtype theory कुल मिलाकर असंगतियों से भरी गड़बड़ चीज है, लेकिन यह उन दुर्लभ मामलों में से है जहां सभी काफी consistent हैं। undergraduate में मैंने कैसे लिखा था, यह जानने के लिए देखा तो पाया कि मैंने भी अच्छे से symmetric तरीके से लिखा था: https://dvt.name/logic/horse2.pdf
x: X“colon के बाद explanation आती है” वाले usage से match करता हैयानी
variable x: It’s an X.जैसाage: intको English में “person’s age: an integer” की तरह आसानी से पढ़ा जा सकता हैइसलिए colon मुझे कभी खास परेशान करने वाला नहीं लगा