हास्केल में "जस्ट" सिंटैक्स का क्या अर्थ है?


118

मैंने इस खोजशब्द के वास्तविक विवरण के लिए इंटरनेट को परिमार्जित किया है। हर हास्केल ट्यूटोरियल जिसे मैंने अभी देखा है, इसे बेतरतीब ढंग से उपयोग करना शुरू कर देता है और यह कभी नहीं बताता है कि यह क्या करता है (और मैंने कई को देखा है)।

यहां रियल वर्ल्ड हास्केल का एक मूल कोड है जो उपयोग करता है Just। मैं समझता हूं कि कोड क्या करता है, लेकिन मुझे समझ नहीं आता है कि उद्देश्य या कार्य क्या Justहै।

lend amount balance = let reserve    = 100
                      newBalance = balance - amount
                  in if balance < reserve
                     then Nothing
                     else Just newBalance

मैंने जो कुछ भी देखा है, वह Maybeटाइपिंग से संबंधित है , लेकिन मैं सीखने में कामयाब रहा हूं।

क्या Justमतलब है की एक अच्छी व्याख्या बहुत सराहना की जाएगी।

जवाबों:


211

यह वास्तव में सिर्फ एक सामान्य डेटा कंस्ट्रक्टर है जो प्रील्यू में परिभाषित होने के लिए होता है , जो मानक पुस्तकालय है जो हर मॉड्यूल में स्वचालित रूप से आयात किया जाता है।

क्या हो सकता है, संरचनात्मक रूप से

परिभाषा कुछ इस तरह दिखती है:

data Maybe a = Just a
             | Nothing

यह घोषणा एक प्रकार को परिभाषित करती है Maybe a, जो कि एक प्रकार के चर द्वारा परिचालित होती है a, जिसका अर्थ है कि आप इसका उपयोग किसी भी प्रकार के स्थान पर कर सकते हैं a

निर्माण और विनाश

प्रकार में दो निर्माता हैं, Just aऔर Nothing। जब एक प्रकार के कई निर्माता होते हैं, तो इसका मतलब है कि प्रकार का एक मूल्य संभव निर्माणकर्ताओं में से केवल एक के साथ बनाया गया है। इस प्रकार के लिए, एक मान या तो निर्माण किया गया था Justया Nothing, कोई अन्य (गैर-त्रुटि) संभावनाएं नहीं हैं।

चूंकि Nothingकोई पैरामीटर प्रकार नहीं है, जब इसे एक निर्माता के रूप में उपयोग किया जाता है तो यह एक निरंतर मूल्य का नाम देता है जो Maybe aसभी प्रकारों के लिए एक प्रकार का सदस्य है a। लेकिन Justकंस्ट्रक्टर के पास एक प्रकार का पैरामीटर होता है, जिसका अर्थ है कि जब एक कंस्ट्रक्टर के रूप में उपयोग किया जाता aहै Maybe a, तो यह प्रकार से फ़ंक्शन की तरह कार्य करता है , अर्थात इसका प्रकार होता हैa -> Maybe a

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

Maybe aएक पैटर्न मैच में एक मूल्य का उपयोग करने के लिए , आपको प्रत्येक निर्माता के लिए एक पैटर्न प्रदान करने की आवश्यकता है, जैसे:

case maybeVal of
    Nothing   -> "There is nothing!"
    Just val  -> "There is a value, and it is " ++ (show val)

उस स्थिति में अभिव्यक्ति, पहला पैटर्न मैच होगा यदि मूल्य था Nothing, और दूसरा मैच होगा अगर मूल्य के साथ निर्माण किया गया था Just। यदि दूसरा एक मेल खाता है, तो यह valउस पैरामीटर को नाम भी बांधता है जो उस Justकंस्ट्रक्टर को पास किया गया था जब आप जिस मूल्य के खिलाफ मिलान कर रहे थे उसका निर्माण किया गया था।

क्या हो सकता है मतलब

शायद आप पहले से ही परिचित थे कि यह कैसे काम करता है; Maybeमूल्यों के लिए वास्तव में कोई जादू नहीं है, यह सिर्फ एक सामान्य हास्केल बीजीय डेटा प्रकार (एडीटी) है। लेकिन इसका काफी उपयोग किया जाता है क्योंकि यह प्रभावी रूप से "लिफ्ट करता है" या एक प्रकार का विस्तार करता है, जैसे कि Integerआपके उदाहरण से, एक नए संदर्भ में जिसमें इसका एक अतिरिक्त मूल्य ( Nothing) है जो मूल्य की कमी का प्रतिनिधित्व करता है! उस प्रकार की प्रणाली के लिए आवश्यक है कि आप उस अतिरिक्त मूल्य की जांच करें, इससे पहले कि आप Integerउस स्थान पर पहुंच सकें । यह बग की एक उल्लेखनीय संख्या को रोकता है।

कई भाषाएं आज इस प्रकार के "नो-वैल्यू" मूल्य को NULL संदर्भों के माध्यम से संभालती हैं। प्रख्यात कंप्यूटर वैज्ञानिक टोनी होरे (उन्होंने क्विकॉर्ट का आविष्कार किया और ट्यूरिंग अवार्ड विजेता हैं), यह उनकी "अरब डॉलर की गलती" के रूप में है । शायद इसे ठीक करने का एकमात्र तरीका नहीं है, लेकिन यह इसे करने का एक प्रभावी तरीका साबित हुआ है।

शायद एक फ़नकार के रूप में

एक प्रकार को दूसरे प्रकार में बदलने का विचार ऐसा है कि पुराने प्रकार के संचालन को भी नए प्रकार पर काम करने के लिए रूपांतरित किया जा सकता है Functor, जिसे हास्केल प्रकार वर्ग कहा जाता है , जिसके Maybe aपीछे एक उपयोगी उदाहरण है।

Functorनामक एक विधि प्रदान करता है fmap, जो कार्यों को आधार प्रकार (जैसे Integer) से मानों तक ले जाने वाले कार्यों को उठाता है जो कि उठाए गए प्रकार (जैसे जैसे Maybe Integer) से मानों की सीमा होती है । एक मान इस तरह काम करता है के साथ fmapकाम करने के लिए तब्दील एक समारोह Maybe:

case maybeVal of
  Nothing  -> Nothing         -- there is nothing, so just return Nothing
  Just val -> Just (f val)    -- there is a value, so apply the function to it

तो अगर आपके पास एक Maybe Integerमूल्य m_xऔर एक Int -> Intफ़ंक्शन है f, तो आप fmap f m_xफ़ंक्शन fको Maybe Integerबिना किसी चिंता के सीधे लागू करने के लिए कर सकते हैं यदि यह वास्तव में एक मूल्य है या नहीं। वास्तव में, आप मूल्यों के Integer -> Integerलिए उठाए गए कार्यों की एक पूरी श्रृंखला लागू कर सकते Maybe Integerहैं और केवल Nothingएक बार समाप्त होने पर स्पष्ट रूप से जांच करने के बारे में चिंता करना होगा ।

शायद एक मोनाड के रूप में

मुझे यकीन नहीं है कि आप Monadअभी तक की अवधारणा से कितने परिचित हैं , लेकिन आपने IO aपहले कम से कम उपयोग किया है , और टाइप हस्ताक्षर IO aउल्लेखनीय रूप से समान दिखता है Maybe a। हालाँकि IOयह विशेष है कि यह आपके कंस्ट्रक्टरों को आपके सामने उजागर नहीं करता है और इस प्रकार हास्केल रनटाइम सिस्टम द्वारा केवल "रन" किया जा सकता है, यह अभी भी एक Functorहोने के अलावा एक है Monad। वास्तव में, एक महत्वपूर्ण अर्थ है जिसमें कुछ अतिरिक्त विशेषताओं Monadके Functorसाथ एक विशेष प्रकार का एक प्रकार है, लेकिन यह उस स्थान पर नहीं है।

वैसे भी, मैप्स IOनए प्रकारों को पसंद करते हैं जो "अभिकलन जो मूल्यों में परिणत होते हैं" का प्रतिनिधित्व करते हैं और आप फ़ंक्शन को Monadप्रकारों में उठा सकते हैं, fmapजैसे एक बहुत -समान फ़ंक्शन के माध्यम से, जो liftMएक नियमित फ़ंक्शन को "अभिकलन" में बदल देता है, जिसके परिणामस्वरूप मूल्य का मूल्यांकन करके प्राप्त किया जाता है। समारोह।"

आपने शायद अनुमान लगाया है (यदि आपने इसे दूर तक पढ़ा है) जो कि Maybeएक भी है Monad। यह "अभिकलन का प्रतिनिधित्व करता है जो एक मूल्य को वापस करने में विफल हो सकता है"। fmapउदाहरण के साथ , यह आपको प्रत्येक चरण के बाद त्रुटियों की स्पष्ट जाँच किए बिना संगणनाओं का एक पूरा गुच्छा बनाने की सुविधा देता है। और वास्तव में, जिस तरह से Monadउदाहरण का निर्माण किया जाता है, Maybeमूल्यों का एक संगणना सामने आते ही रुक जाताNothing है, इसलिए यह एक तत्काल गर्भपात की तरह है या एक संगणना के बीच में एक वैधता वापसी।

हो सकता है आपने लिखा हो

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

उम्मीद है कि आप Maybeअब इसके प्रकार और इसके निर्माणकर्ताओं को समझेंगे , लेकिन अगर अभी भी कुछ स्पष्ट नहीं है, तो मुझे बताएं!


19
क्या शानदार जवाब है! यह उल्लेख किया जाना चाहिए कि हास्केल अक्सर उपयोग करता है Maybeजहां अन्य भाषाएं उपयोग करती हैं nullया nil( NullPointerExceptionहर कोने में गंदा एस लुकिंग के साथ )। अब अन्य भाषाएं भी इस निर्माण का उपयोग करना शुरू कर देती हैं, जैसे: स्काला Option, और यहां तक ​​कि जावा 8 का भी Optionalप्रकार होगा।
लांडे

3
यह एक उत्कृष्ट व्याख्या है। कई स्पष्टीकरणों को मैंने पढ़ा है कि इस विचार पर संकेत दिया गया है कि बस शायद प्रकार के लिए एक निर्माता है, लेकिन किसी ने कभी भी इसे स्पष्ट नहीं किया है।
रीम

@ लांडे, सुझाव के लिए धन्यवाद। मैंने अशक्त संदर्भों के खतरे का उल्लेख करने के लिए एक संपादन किया।
लेवी पियर्सन

@ लांडे विकल्प प्रकार 70 के दशक में एमएल के आसपास रहा है, यह अधिक संभावना है कि स्काला ने इसे वहां से उठाया क्योंकि स्काला एमएल के नामकरण सम्मेलन का उपयोग करता है, कुछ और कोई नहीं के साथ विकल्प।
पत्थर का

@ लेन्डी ऐप्पल की स्विफ्ट वैकल्पिक रूप से भी बहुत उपयोग करती है
जामिन

37

वर्तमान उत्तरों में से अधिकांश उच्च तकनीकी स्पष्टीकरण हैं कि Justमित्र कैसे काम करते हैं; मैंने सोचा कि मैं यह समझाने के लिए अपने हाथ की कोशिश कर सकता हूं कि यह किस लिए है।

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

हास्केल आपको स्पष्ट रूप से उन स्थानों को चिह्नित करके इस समस्या को हल करता है जहां आपके पास Nothing(इसका एक संस्करण null) हो सकता है। मूल रूप से, यदि आपका फ़ंक्शन सामान्य रूप से प्रकार लौटाएगा Foo, तो इसके बजाय उसे प्रकार वापस करना चाहिए Maybe Foo। यदि आप इंगित करना चाहते हैं कि कोई मूल्य नहीं है, तो वापस लौटें Nothing। यदि आप एक मूल्य वापस करना चाहते हैं bar, तो आपको इसके बजाय वापस लौटना चाहिए Just bar

इसलिए मूल रूप से, यदि आपके पास नहीं हो सकता है Nothing, तो आपको जरूरत नहीं है Just। यदि आपके पास हो सकता है Nothing, तो आपको जरूरत है Just

कुछ भी जादुई नहीं है Maybe; यह हास्केल प्रकार प्रणाली पर बनाया गया है। इसका मतलब है कि आप इसके साथ सभी सामान्य हास्केल पैटर्न मिलान चाल का उपयोग कर सकते हैं ।


1
अन्य उत्तरों के आगे बहुत अच्छा जवाब है, लेकिन मुझे लगता है कि यह अभी भी एक कोड उदाहरण से लाभ
उठाएगा

13

एक प्रकार को देखते हुए t, का एक मूल्य प्रकार Just tका एक मौजूदा मूल्य है t, जहां Nothingएक मूल्य तक पहुंचने में विफलता का प्रतिनिधित्व करता है, या एक ऐसा मामला जहां मूल्य का होना अर्थहीन होगा।

आपके उदाहरण में, एक नकारात्मक संतुलन होने का कोई मतलब नहीं है, और इसलिए यदि ऐसा होता है, तो इसे बदल दिया जाता है Nothing

एक अन्य उदाहरण के लिए, यह डिवीजन में इस्तेमाल किया जा सकता है, जो एक डिवीजन फ़ंक्शन को परिभाषित करता है, जो लेता है aऔर b, और Just a/bअगर bनॉनज़रो है, और Nothingअन्यथा। इसका उपयोग अक्सर इस तरह किया जाता है, अपवादों के लिए एक सुविधाजनक विकल्प के रूप में, या अपने पहले के उदाहरण की तरह, उन मूल्यों को बदलने के लिए जो समझ में नहीं आते हैं।


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

7
यदि आप Justहटाते हैं, तो आपका कोड टाइपकॉच नहीं करेगा। इसका कारण Justउचित प्रकार बनाए रखना है। एक प्रकार है (ए मोनड, वास्तव में, लेकिन यह सिर्फ एक प्रकार के रूप में सोचना आसान है) Maybe t, जिसमें फॉर्म के तत्व शामिल हैं Just tऔर Nothing। चूंकि Nothingप्रकार है Maybe t, एक अभिव्यक्ति जो Nothingया तो टाइप कर सकती है या कुछ प्रकार tका मान ठीक से टाइप नहीं किया गया है। यदि कोई फ़ंक्शन Nothingकुछ मामलों में लौटता है, तो उस फ़ंक्शन का उपयोग करने वाले किसी भी अभिव्यक्ति के लिए उस ( isJustया एक केस स्टेटमेंट) की जांच करने का कुछ तरीका होना चाहिए , ताकि सभी संभावित मामलों को संभाल सकें।
क़ाफला

2
तो बस बस वहाँ हो सकता है लगातार प्रकार के अनुरूप हो क्योंकि एक नियमित रूप से शायद टी प्रकार में नहीं है। अब सब कुछ बहुत स्पष्ट है। धन्यवाद!
रीम

3
@qaphla: इसके बारे में आपकी टिप्पणी "एक भिक्षु, वास्तव में, [...]" भ्रामक है। Maybe t है सिर्फ एक प्रकार। तथ्य यह है कि इसके Monadलिए एक उदाहरण Maybeहै जो इसे एक प्रकार में परिवर्तित नहीं करता है।
सारा

2

कुल फ़ंक्शन a-> b प्रकार के हर संभव मान के लिए टाइप b का मान पा सकता है।

हास्केल में सभी कार्य कुल नहीं हैं। इस विशेष मामले में फ़ंक्शन lendकुल नहीं है - यह उस स्थिति के लिए परिभाषित नहीं है जब संतुलन रिजर्व से कम है (हालांकि, मेरे स्वाद के अनुसार, यह नए अर्थ को आरक्षित करने की तुलना में कम होने की अनुमति देने के लिए अधिक समझ में आता है - जैसा कि आप 101 से उधार ले सकते हैं। 100 का संतुलन)।

अन्य डिज़ाइन जो गैर-कुल कार्यों से निपटते हैं:

  • इनपुट मूल्य की जाँच करने पर अपवाद न फेंकना सीमा के लायक नहीं है
  • एक विशेष मूल्य (आदिम प्रकार) लौटाएं: पसंदीदा विकल्प पूर्णांक कार्यों के लिए एक नकारात्मक मान है जो प्राकृतिक संख्याओं को वापस करने के लिए है (उदाहरण के लिए, String.indexOf - जब कोई विकल्प नहीं मिलता है, तो लौटा हुआ सूचकांक आमतौर पर नकारात्मक होने के लिए डिज़ाइन किया गया है)
  • एक विशेष मान (पॉइंटर) लौटाएं: NULL या कुछ ऐसा
  • चुपचाप बिना कुछ किए लौटें: उदाहरण के लिए, lendपुराने बैलेंस को लौटाने के लिए लिखा जा सकता है, अगर उधार देने की शर्त पूरी नहीं हुई
  • एक विशेष मूल्य लौटाएं: कुछ भी नहीं (या कुछ त्रुटि वर्णन वस्तु को छोड़ कर)

ये भाषाओं में आवश्यक डिजाइन सीमाएं हैं जो कार्यों की समग्रता को लागू नहीं कर सकती हैं (उदाहरण के लिए, एजडा कर सकती हैं, लेकिन यह अन्य जटिलताओं की ओर जाता है, जैसे कि ट्यूरिंग-अपूर्ण होना)।

एक विशेष मूल्य को वापस करने या अपवादों को फेंकने में समस्या यह है कि फोन करने वाले के लिए गलती से इस तरह की संभावना से निपटना आसान है।

एक विफलता को चुपचाप छोड़ने की समस्या भी स्पष्ट है - आप यह कह रहे हैं कि कॉलर फ़ंक्शन के साथ क्या कर सकता है। उदाहरण के लिए, यदि lendपुराना शेष राशि लौटा दी गई है , तो कॉलर के पास यह जानने का कोई तरीका नहीं है कि क्या संतुलन बदल गया है। यह उद्देश्य के आधार पर एक समस्या हो सकती है या नहीं हो सकती है।

हास्केल का समाधान कॉल के प्रकार से निपटने के लिए Maybe aया Either error aफ़ंक्शन के रिटर्न प्रकार के कारण आंशिक फ़ंक्शन के कॉलर को मजबूर करता है ।

इस तरह lendसे परिभाषित किया गया है, एक ऐसा कार्य है जो हमेशा नए संतुलन की गणना नहीं करता है - कुछ परिस्थितियों के लिए नए संतुलन को परिभाषित नहीं किया जाता है। हम इस स्थिति को कॉल करने वाले को संकेत देते हैं कि या तो विशेष मूल्य कुछ भी नहीं लौटाए, या जस्ट में नया शेष राशि लपेटकर। कॉलर को अब चुनने की स्वतंत्रता है: या तो एक विशेष तरीके से उधार देने में विफलता को संभालें, या पुराने संतुलन को अनदेखा करें और उपयोग करें - उदाहरण के लिए maybe oldBalance id $ lend amount oldBalance


-1

फ़ंक्शन if (cond :: Bool) then (ifTrue :: a) else (ifFalse :: a)में एक ही प्रकार का ifTrueऔर होना चाहिए ifFalse

इसलिए, जब हम लिखते हैं then Nothing, तो हमें Maybe aटाइप का उपयोग करना चाहिएelse f

if balance < reserve
       then (Nothing :: Maybe nb)         -- same type
       else (Just newBalance :: Maybe nb) -- same type

1
मुझे यकीन है कि तुम सच में गहरी यहाँ कुछ कहने के लिए मतलब कर रहा हूँ
sehe

1
हास्केल में प्रकार का अनुमान है। के प्रकार राज्य के लिए कोई जरूरत नहीं है Nothingऔर Just newBalanceस्पष्ट रूप से।
rightfold

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