फ़ंक्शन मापदंडों का एनोटेट क्यों नहीं?


28

इस प्रश्न को उत्तर देने योग्य बनाने के लिए, मान लें कि प्रोग्रामर के दिमाग में अस्पष्टता की लागत कहीं अधिक है तो कुछ अतिरिक्त कीस्ट्रोक्स।

यह देखते हुए कि, मैं अपने साथियों को अपने कार्य मापदंडों की व्याख्या करने की अनुमति क्यों दूंगा ? निम्नलिखित कोड को एक उदाहरण के रूप में लें जो कोड का एक अधिक जटिल टुकड़ा हो सकता है:

let foo x y = x + y

अब, टूलटिप की एक त्वरित परीक्षा आपको दिखाएगी कि F # ने आपको x और y के ints के लिए निर्धारित किया है। यदि आपका इरादा यही है, तो सब ठीक है। लेकिन मुझे नहीं पता कि क्या आप का इरादा है। क्या होगा अगर आपने दो तारों को एक साथ जोड़ने के लिए यह कोड बनाया था? या क्या होगा अगर मुझे लगता है कि आप शायद युगल को जोड़ने के लिए हैं? या क्या होगा अगर मैं सिर्फ अपने प्रकार को निर्धारित करने के लिए हर एक फ़ंक्शन पैरामीटर पर माउस को हॉवर नहीं करना चाहता?

अब इसे एक उदाहरण के रूप में लें:

let foo x y = "result: " + x + y

F # अब यह मान लेता है कि आपने स्ट्रिंग को संक्षिप्त करने का इरादा किया है, इसलिए x और y को स्ट्रिंग्स के रूप में परिभाषित किया गया है। हालाँकि, आपके कोड को बनाए रखने वाले गरीब schmuck के रूप में, मैं इसे देख सकता हूं और आश्चर्यचकित हो सकता हूं कि शायद आपने x और y (ints) को एक साथ जोड़ने का इरादा किया था और फिर परिणाम को UI उद्देश्यों के लिए स्ट्रिंग में जोड़ दिया।

निश्चित रूप से ऐसे सरल उदाहरणों के लिए कोई इसे जाने दे सकता है, लेकिन स्पष्ट प्रकार के एनोटेशन की नीति क्यों नहीं लागू करता है?

let foo (x:string) (y:string) = "result: " + x + y

असंदिग्ध होने में क्या हानि है? निश्चित रूप से, एक प्रोग्रामर गलत प्रकारों को चुन सकता है कि वे क्या करने की कोशिश कर रहे हैं, लेकिन कम से कम मुझे पता है कि वे इसका इरादा रखते थे, कि यह सिर्फ एक निरीक्षण नहीं था।

यह एक गंभीर सवाल है ... मैं अभी भी एफ # के लिए बहुत नया हूं और अपनी कंपनी के लिए निशान को धधक रहा हूं। जिन मानकों को मैं अपनाता हूं, वे संभवतः सभी भविष्य के एफ # कोडिंग के लिए आधार होंगे, अंतहीन कॉपी-पेस्टिंग में एम्बेडेड होंगे जो मुझे यकीन है कि आने वाले वर्षों के लिए संस्कृति को आगे बढ़ाएगा।

तो ... क्या F # के प्रकार के निष्कर्ष के बारे में कुछ विशेष है जो इसे आवश्यक होने पर केवल एनोटेट करते हुए इसे धारण करने के लिए एक मूल्यवान सुविधा बनाता है? या विशेषज्ञ एफ # -ers गैर-तुच्छ अनुप्रयोगों के लिए अपने मापदंडों को एनोटेट करने की आदत बनाते हैं?


एनोटेट संस्करण कम सामान्य है। यह उसी कारण के लिए है जिसे आप अधिमानतः IEnumerable <> हस्ताक्षर में उपयोग करते हैं न कि SortedSet <> में।
पैट्रिक

2
@ पैट्रिक - नहीं, यह नहीं है, क्योंकि एफ # स्ट्रिंग प्रकार का जिक्र है। मैंने फ़ंक्शन के हस्ताक्षर नहीं बदले हैं, केवल इसे स्पष्ट किया है।
JDB

1
@ पैट्रिक - और यहां तक ​​कि अगर यह सच था, तो क्या आप समझा सकते हैं कि यह एक बुरी चीज क्यों है? शायद हस्ताक्षर कम सामान्य होना चाहिए , अगर यही प्रोग्रामर का इरादा था। शायद अधिक सामान्य हस्ताक्षर वास्तव में समस्याएं पैदा कर रहे हैं, लेकिन मुझे यकीन नहीं है कि प्रोग्रामर कितनी बड़ी शोध के बिना होने का इरादा रखता है।
JDB

1
मुझे लगता है कि यह कहना उचित है कि कार्यात्मक भाषाओं में, आप सामान्यता पसंद करते हैं, और अधिक विशिष्ट मामले में एनोटेट करते हैं; जैसे कि जब आप बेहतर प्रदर्शन चाहते हैं, और इसे टाइप हिंटिंग का उपयोग करके प्राप्त कर सकते हैं। हर जगह एनोटेट कार्यों का उपयोग करने के लिए आपको प्रत्येक विशिष्ट प्रकार के लिए अधिभार लिखना होगा, जो सामान्य मामले में वारंट नहीं किया जा सकता है।
रॉबर्ट हार्वे

जवाबों:


30

मैं एफ # का उपयोग नहीं करता हूं, लेकिन हास्केल में इसे उच्च-स्तरीय परिभाषाओं और कभी-कभी स्थानीय परिभाषाओं को एनोटेट करने के लिए अच्छा रूप माना जाता है, भले ही भाषा में व्यापक प्रकार की धारणा हो। यह कुछ कारणों से है:

  • पढ़ना
    जब आप जानना चाहते हैं कि किसी फ़ंक्शन का उपयोग कैसे करें, तो यह उपलब्ध प्रकार के हस्ताक्षर के लिए अविश्वसनीय रूप से उपयोगी है। आप इसे स्वयं पढ़ सकते हैं या अपने लिए इसे करने के लिए साधनों पर निर्भर रहने के बजाय इसे पढ़ सकते हैं।


  • जब आप किसी फ़ंक्शन को बदलना चाहते हैं, तो पुनर्संरचना करना एक स्पष्ट हस्ताक्षर होने से आपको कुछ आश्वासन मिलता है कि आपके परिवर्तन मूल कोड के इरादे को बनाए रखते हैं। टाइप-इनफ़ॉर्मेड भाषा में, आप पा सकते हैं कि अत्यधिक पॉलीमॉर्फिक कोड टाइपटेक करेगा, लेकिन ऐसा नहीं है जो आपने इरादा किया था। प्रकार हस्ताक्षर एक "बाधा" है जो एक अंतरफलक पर टाइप जानकारी को समेटता है।


  • हस्केल में प्रदर्शन , एक फ़ंक्शन के अनुमानित प्रकार को अतिभारित किया जा सकता है (टाइपकास्टेस के माध्यम से), जो एक रनटाइम प्रेषण का कारण बन सकता है। संख्यात्मक प्रकारों के लिए, डिफ़ॉल्ट प्रकार एक मनमाना-सटीक पूर्णांक है। यदि आपको इन सुविधाओं की पूर्ण व्यापकता की आवश्यकता नहीं है, तो आप फ़ंक्शन को विशिष्ट प्रकार की आवश्यकता के लिए विशेषज्ञता प्रदान करके प्रदर्शन में सुधार कर सकते हैं।

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


3
यह एक बहुत ही उचित और अच्छी तरह से संतुलित प्रतिक्रिया की तरह लगता है।
JDB

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

4
हास्केल में यह आपके कार्यों को एनोटेट करने के लिए सही माना जाता है, लेकिन मेरा मानना ​​है कि मुहावरेदार F # और OCaml एनोटेशन को छोड़ देते हैं जब तक कि अस्पष्टता को दूर करने के लिए आवश्यक न हो। यह कहना हानिकारक नहीं है (हालांकि F # में टिप्पणी करने के लिए वाक्य रचना हास्केल की तुलना में बदसूरत है)।
KChaloux

4
@KChaloux OCaml में, इंटरफ़ेस ( .mli) फ़ाइल में पहले से ही टाइप एनोटेशन हैं (यदि आप एक लिखते हैं, जिसे आप दृढ़ता से प्रोत्साहित करते हैं। टाइप एनोटेशन परिभाषाओं से छूट जाते हैं क्योंकि वे इंटरफ़ेस के साथ निरर्थक होंगे।
गिल्स ' SO- बुराई को रोकना '

1
@Gilles @KChaloux वास्तव में, एफ # सिग्नेचर ( .fsi) फाइलों में एक ही, एक कैविएट के साथ: एफ # टाइप इंट्रेंस के लिए सिग्नेचर फाइल का उपयोग नहीं करता है, इसलिए यदि कार्यान्वयन में कुछ अस्पष्ट है, तो भी आपको इसे फिर से एनोटेट करना होगा। books.google.ca/…
Yawar Amin

1

जॉन ने एक उचित जवाब दिया, जिसे मैं यहां नहीं दोहराऊंगा। हालांकि मैं आपको एक विकल्प दिखाऊंगा जो आपकी आवश्यकताओं को पूरा कर सकता है और इस प्रक्रिया में आपको हां / ना के अलावा एक अलग प्रकार का उत्तर दिखाई देगा।

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

उदाहरण के लिए:

/// Parser that requires a specific item.

// a (tok : 'a) : ('a list -> 'a * 'a list)                     // generic
// a (tok : string) : (string list -> string * string list)     // string
// a (tok : token)  : (token list  -> token  * token list)      // token

या

/// Parses iterated left-associated binary operator.


// leftbin (prs : 'a -> 'b * 'c) (sep : 'c -> 'd * 'a) (cons : 'd -> 'b -> 'b -> 'b) (err : string) : ('a -> 'b * 'c)                                                                                    // generic
// leftbin (prs : string list -> string * string list) (sep : string list -> string * string list) (cons : string -> string -> string -> string) (err : string) : (string list -> string * string list)  // string
// leftbin (prs : token list  -> token  * token list)  (sep : token list  -> token  * token list)  (cons : token  -> token  -> token  -> token)  (err : string) : (token list  -> token  * token list)   // token

चूंकि कोड कॉपीराइट है इसलिए मैं इसे यहां शामिल नहीं करूंगा लेकिन यह Github पर उपलब्ध है । इसे यहाँ कॉपी न करें।

कार्य करने के लिए उन्हें सामान्य पैरामीटर के साथ छोड़ दिया जाना चाहिए, लेकिन मैं उन टिप्पणियों को शामिल करता हूं जो फ़ंक्शन के उपयोग के आधार पर अनुमान प्रकार दिखाते हैं। यह उपयोग के लिए फ़ंक्शन सामान्य छोड़ते समय रखरखाव के लिए फ़ंक्शन को समझना आसान बनाता है।


1
आप कार्य में सामान्य संस्करण क्यों नहीं लिखेंगे? क्या वह काम नहीं करेगा?
svick

@svick मुझे आपका प्रश्न समझ में नहीं आ रहा है। क्या आपका मतलब है कि मैंने फ़ंक्शन परिभाषा से प्रकार छोड़ दिए हैं, लेकिन जेनेरिक प्रकारों को फ़ंक्शन परिभाषाओं में जोड़ा जा सकता है क्योंकि सामान्य प्रकार फ़ंक्शन के अर्थ को नहीं बदलेंगे? यदि ऐसा है तो व्यक्तिगत प्राथमिकता अधिक है। जब मैंने पहली बार F # से शुरुआत की तो मैंने उन्हें जोड़ा। जब मैंने एफ # के अधिक उन्नत उपयोगकर्ताओं के साथ काम करना शुरू कर दिया, तो उन्होंने उन्हें टिप्पणियों के रूप में छोड़ दिया जाना पसंद किया, क्योंकि वहां हस्ताक्षर के बिना कोड को संशोधित करना आसान था। ...
गाय कोडर

लंबे समय में जिस तरह से मैं उन्हें दिखाता हूं क्योंकि कोड काम करने के बाद टिप्पणियों ने सभी के लिए काम किया। जब मैं एक फ़ंक्शन लिखना शुरू करता हूं तो मैं टाइप करता हूं। एक बार मेरे पास कार्य करने के बाद, मैं टाइप सिग्नेचर को कमेंट में ले जाता हूं और यथासंभव कई प्रकार के रिमूव करता हूं। F # के साथ कुछ बार आपको अनुमान लगाने में मदद करने के लिए टाइप करने की आवश्यकता होती है। थोड़ी देर के लिए मैं लेट और = के साथ टिप्पणी बनाने के लिए प्रयोग कर रहा था ताकि आप परीक्षण के लिए लाइन को अनलॉक्ड कर सकें, फिर जब यह किया जाए तो फिर से टिप्पणी करें, लेकिन वे मूर्ख दिखे और एक लेट और = जोड़ना मुश्किल नहीं है।
गाय कोडर

अगर इन टिप्पणियों का जवाब है जो आप पूछ रहे हैं तो मुझे बताएं ताकि मैं उन्हें जवाब में स्थानांतरित कर सकूं।
गाय कोडर

2
इसलिए जब आप कोड को संशोधित करते हैं, तो आप टिप्पणियों को संशोधित नहीं करते हैं, जो पुरानी प्रलेखन के लिए अग्रणी हैं? यह मेरे लिए एक लाभ की तरह नहीं है। और मैं वास्तव में यह नहीं देखता कि गन्दा टिप्पणी गन्दे कोड से बेहतर कैसे हो सकती है। मेरे लिए, ऐसा लगता है कि यह दृष्टिकोण दो विकल्पों के नुकसान को जोड़ता है।
svick

-8

बग की संख्या एक कार्यक्रम में पात्रों की संख्या के लिए सीधे आनुपातिक है!

यह आमतौर पर कोड की लाइनों के आनुपातिक होने के रूप में कीड़े की संख्या के रूप में कहा जाता है। लेकिन कोड की समान मात्रा के साथ कम लाइनें होने से समान मात्रा में बग मिलते हैं।

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


5
"बग्स की संख्या एक कार्यक्रम में पात्रों की संख्या के लिए सीधे आनुपातिक है!" इसलिए हम सभी को एपीएल पर स्विच करना चाहिए ? बहुत अधिक कठिन होना एक समस्या है, ठीक वैसे ही जैसे बहुत अधिक क्रिया होना।
svick

5
" इस प्रश्न को उत्तर देने योग्य बनाने के लिए, मान लें कि एक प्रोग्रामर के दिमाग में अस्पष्टता की लागत बहुत अधिक है तो कुछ अतिरिक्त कीस्ट्रोक्स। "
JDB
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.