यहाँ हैस्केल यह कैसे करता है: (लिपस्केल के कथनों से बिलकुल भी अंतर नहीं है क्योंकि हास्केल ऑब्जेक्ट-ओरिएंटेड भाषा नहीं है)।
चेतावनी: आगे एक गंभीर हास्केल फैनबॉय से लंबे घुमावदार जवाब।
टी एल; डॉ
इस उदाहरण से पता चलता है कि हस्केल सी # से कितना अलग है। एक निर्माणकर्ता को संरचना निर्माण के रसद को सौंपने के बजाय, इसे आसपास के कोड में संभाला जाना चाहिए। Nothing
फसल के लिए एक शून्य (या हास्केल) मूल्य मूल्य के लिए कोई रास्ता नहीं है जहां हम एक गैर-शून्य मूल्य की उम्मीद कर रहे हैं क्योंकि शून्य मान केवल विशेष आवरण प्रकारों के भीतर हो सकते हैं जिन्हें बुलाया के Maybe
साथ विनिमेय नहीं है / सीधे, नियमित रूप से परिवर्तनीय के लिए, गैर- अशक्त प्रकार के। इसे में लपेटकर अशक्त किए गए मान का उपयोग करने के लिए Maybe
, हमें पहले पैटर्न मिलान का उपयोग करके मूल्य निकालना होगा, जो हमें नियंत्रण प्रवाह को एक शाखा में मोड़ने के लिए मजबूर करता है, जहां हम निश्चित रूप से जानते हैं कि हमारे पास एक गैर-शून्य मान है।
इसलिए:
क्या हम हमेशा यह जान सकते हैं कि गैर-अशोभनीय संदर्भ किसी भी परिस्थिति में कभी भी अमान्य नहीं होगा?
हाँ। Int
और Maybe Int
दो पूरी तरह से अलग प्रकार हैं। Nothing
सादे में खोजना Int
स्ट्रिंग "मछली" को खोजने के लिए तुलनीय होगा Int32
।
संदर्भ प्रकार के गैर-अशक्त क्षेत्र के साथ किसी वस्तु के निर्माता के बारे में क्या?
कोई मुद्दा नहीं: हास्केल में मूल्य निर्माता कुछ भी नहीं कर सकते हैं, लेकिन उनके द्वारा दिए गए मूल्यों को लें और उन्हें एक साथ रखें। कंस्ट्रक्टर को कॉल करने से पहले सभी आरंभिक तर्क दिए जाते हैं।
ऐसे ऑब्जेक्ट के अंतिम रूप में क्या है, जहां ऑब्जेक्ट को अंतिम रूप दिया गया है क्योंकि संदर्भ में भरने वाला कोड एक अपवाद फेंक दिया था?
हास्केल में कोई फाइनल नहीं है, इसलिए मैं वास्तव में इसे संबोधित नहीं कर सकता। हालाँकि मेरी पहली प्रतिक्रिया अभी भी है।
पूर्ण उत्तर :
हास्केल में कोई अशक्त नहीं है और अशक्त Maybe
का प्रतिनिधित्व करने के लिए डेटा प्रकार का उपयोग करता है । हो सकता है कि इस तरह परिभाषित एक अल्गब्राटिक डेटा प्रकार हो :
data Maybe a = Just a | Nothing
हास्केल से अपरिचित आप में से उन लोगों के लिए, "ए Maybe
या तो ए Nothing
या Just a
" है। विशेष रूप से:
Maybe
है प्रकार निर्माता : यह एक सामान्य वर्ग (जहां के रूप में की (गलत) सोचा जा सकता है a
प्रकार चर है)। C # सादृश्य है class Maybe<a>{}
।
Just
एक वैल्यू कंस्ट्रक्टर है : यह एक ऐसा फंक्शन है जो टाइप का एक तर्क लेता है a
और उस वैल्यू को टाइप Maybe a
करता है जिसमें वैल्यू होती है। तो कोड x = Just 17
के अनुरूप है int? x = 17;
।
Nothing
एक और मूल्य निर्माता है, लेकिन यह कोई तर्क नहीं लेता है और Maybe
लौटे का "कुछ भी नहीं" के अलावा कोई मूल्य नहीं है। x = Nothing
के अनुरूप है int? x = null;
(यह मानकर कि हम a
हास्केल में होने के लिए विवश हैं Int
, जिसे लिखकर किया जा सकता है x = Nothing :: Maybe Int
)।
अब जब Maybe
प्रकार की मूल बातें खत्म हो गई हैं, तो हास्केल ओपी के प्रश्न में चर्चा किए गए मुद्दों से कैसे बचते हैं?
खैर, हास्केल वास्तव में अब तक चर्चा की गई अधिकांश भाषाओं से अलग है, इसलिए मैं कुछ बुनियादी भाषा सिद्धांतों की व्याख्या करके शुरू करूंगा।
सबसे पहले, हास्केल में, सब कुछ अपरिवर्तनीय है । सब कुछ। नाम मानों को संदर्भित करते हैं, स्मृति स्थानों को नहीं जहां मूल्यों को संग्रहीत किया जा सकता है (यह अकेले बग उन्मूलन का एक बड़ा स्रोत है)। सी #, जहां चर घोषणा और काम दो अलग-अलग संचालन, हास्केल मूल्यों में उनके मूल्य को परिभाषित द्वारा बनाई गई हैं कर रहे हैं के विपरीत (जैसे x = 15
, y = "quux"
, z = Nothing
), कभी नहीं बदल सकता है। इसलिए, जैसे कोड:
ReferenceType x;
हास्केल में संभव नहीं है। मानों को शुरू करने में कोई समस्या नहीं है null
क्योंकि सब कुछ स्पष्ट रूप से एक मूल्य के लिए प्रारंभिक होना चाहिए ताकि यह अस्तित्व में हो।
दूसरे, हास्केल एक वस्तु-उन्मुख भाषा नहीं है : यह विशुद्ध रूप से कार्यात्मक भाषा है, इसलिए शब्द के सख्त अर्थों में कोई वस्तु नहीं है। इसके बजाय, बस कार्य (मूल्य निर्माता) हैं जो अपने तर्क लेते हैं और एक समामेलित संरचना लौटाते हैं।
अगला, कोई अनिवार्य शैली कोड नहीं है। इसके द्वारा, मेरा मतलब है कि अधिकांश भाषाएँ इस तरह से एक पैटर्न का अनुसरण करती हैं:
do thing 1
add thing 2 to thing 3
do thing 4
if thing 5:
do thing 6
return thing 7
कार्यक्रम व्यवहार को निर्देशों की एक श्रृंखला के रूप में व्यक्त किया जाता है। ऑब्जेक्ट-ओरिएंटेड भाषाओं में, क्लास और फंक्शन की घोषणाएं भी प्रोग्राम फ्लो में एक बड़ी भूमिका निभाती हैं, लेकिन सार है, प्रोग्राम के निष्पादन का "मांस" निष्पादित होने के लिए निर्देशों की एक श्रृंखला का रूप लेता है।
हास्केल में, यह संभव नहीं है। इसके बजाय, कार्यक्रम का प्रवाह पूरी तरह से कार्यों के जंजीरों से तय होता है। यहां तक कि ऑपरेटर do
को अनाम कार्यों को पारित करने के लिए अनिवार्य-दिखने वाली नोटबंदी केवल वाक्यात्मक चीनी है >>=
। सभी कार्य इस प्रकार हैं:
<optional explicit type signature>
functionName arg1 arg2 ... argn = body-expression
जहां body-expression
कुछ भी हो सकता है जो एक मूल्य का मूल्यांकन करता है। जाहिर है कि अधिक वाक्यविन्यास सुविधाएँ उपलब्ध हैं लेकिन मुख्य बिंदु बयानों के अनुक्रमों की पूर्ण अनुपस्थिति है।
अंत में, और शायद सबसे महत्वपूर्ण बात, हास्केल का प्रकार प्रणाली अविश्वसनीय रूप से सख्त है। अगर मुझे हास्केल के प्रकार प्रणाली के केंद्रीय डिजाइन दर्शन को संक्षेप में प्रस्तुत करना था, तो मैं कहूंगा: "जितना संभव हो उतना संभव संकलन समय पर गलत तरीके से करें ताकि जितना संभव हो सके रनटाइम पर गलत हो।" कोई भी अंतर्निहित रूपांतरण नहीं हैं (जो एक Int
को बढ़ावा देना चाहते हैं Double
? fromIntegral
फ़ंक्शन का उपयोग करें )। केवल संभवत: एक अमान्य मान रनटाइम पर होता है, Prelude.undefined
जिसका उपयोग करना है (जो कि स्पष्ट रूप से बस वहां होना है और निकालना असंभव है )।
इस सब को ध्यान में रखते हुए, आइए हम अमोन के "टूटे" उदाहरण को देखें और हास्केल में इस कोड को फिर से व्यक्त करने का प्रयास करें। सबसे पहले, डेटा घोषणा (नामित क्षेत्रों के लिए रिकॉर्ड सिंटैक्स का उपयोग करके):
data NotSoBroken = NotSoBroken {foo :: Foo, bar :: Bar }
( foo
और bar
वास्तविक क्षेत्रों के बजाय यहां अनाम क्षेत्रों में वास्तव में एक्सेसर फ़ंक्शन हैं, लेकिन हम इस विवरण को अनदेखा कर सकते हैं)।
NotSoBroken
मूल्य निर्माता एक लेने के अलावा अन्य कोई भी कार्रवाई करने में असमर्थ है Foo
और एक Bar
(जो व्यर्थ नहीं कर रहे हैं) और एक बनाने NotSoBroken
उनमें से बाहर। अनिवार्य कोड डालने या खेतों को मैन्युअल रूप से असाइन करने के लिए कोई जगह नहीं है। सभी आरंभीकरण तर्क कहीं और होने चाहिए, सबसे अधिक संभावना एक समर्पित कारखाने के कार्य में।
उदाहरण में, Broken
हमेशा निर्माण विफल रहता है। समान तरीके से NotSoBroken
वैल्यू कंस्ट्रक्टर को तोड़ने का कोई तरीका नहीं है (कोड लिखने के लिए बस कहीं नहीं है), लेकिन हम एक कारखाना फ़ंक्शन बना सकते हैं जो समान रूप से दोषपूर्ण है।
makeNotSoBroken :: Foo -> Bar -> Maybe NotSoBroken
makeNotSoBroken foo bar = Nothing
(पहली पंक्ति एक प्रकार का हस्ताक्षर घोषणा है: makeNotSoBroken
एक Foo
और एक Bar
तर्क के रूप में लेता है और पैदा करता है Maybe NotSoBroken
)।
वापसी प्रकार होना चाहिए Maybe NotSoBroken
और केवल NotSoBroken
इसलिए नहीं कि हमने इसे मूल्यांकन करने के लिए कहा था Nothing
, जो इसके लिए एक मूल्य निर्माता है Maybe
। यदि हम कुछ अलग लिखते हैं तो प्रकार केवल पंक्तिबद्ध नहीं होंगे।
बिल्कुल निरर्थक होने के बावजूद, यह फ़ंक्शन अपने वास्तविक उद्देश्य को भी पूरा नहीं करता है, जैसा कि हम देखेंगे जब हम इसका उपयोग करने का प्रयास करेंगे। आइए एक फ़ंक्शन बनाएं जिसे एक तर्क के रूप में useNotSoBroken
उम्मीद है NotSoBroken
:
useNotSoBroken :: NotSoBroken -> Whatever
( तर्क के रूप में useNotSoBroken
स्वीकार करता है NotSoBroken
और पैदा करता है Whatever
)।
और इसका इस्तेमाल ऐसे करें:
useNotSoBroken (makeNotSoBroken)
अधिकांश भाषा में, इस तरह के व्यवहार से अशक्त सूचक अपवाद हो सकता है। हास्केल में, प्रकार मेल नहीं खाते: makeNotSoBroken
रिटर्न ए Maybe NotSoBroken
, लेकिन useNotSoBroken
उम्मीद है कि ए NotSoBroken
। ये प्रकार विनिमेय नहीं हैं, और कोड संकलित करने में विफल रहता है।
इसके आस-पास जाने के लिए, हम मूल्य case
के ढांचे के आधार पर शाखा के लिए एक बयान का उपयोग कर सकते हैं Maybe
( पैटर्न मिलान नामक एक सुविधा का उपयोग करके ):
case makeNotSoBroken of
Nothing -> --handle situation here
(Just x) -> useNotSoBroken x
स्पष्ट रूप से इस स्निपेट को वास्तव में संकलित करने के लिए कुछ संदर्भों के अंदर रखने की आवश्यकता है, लेकिन यह मूल सिद्धांतों को प्रदर्शित करता है कि हास्केल हलवे कैसे संभालती है। यहाँ उपरोक्त कोड का चरण-दर-चरण स्पष्टीकरण दिया गया है:
- सबसे पहले,
makeNotSoBroken
मूल्यांकन किया जाता है, जो प्रकार के मूल्य का उत्पादन करने की गारंटी है Maybe NotSoBroken
।
case
बयान इस मूल्य की संरचना निरीक्षण करता है।
- यदि मान है
Nothing
, तो "हैंडल स्थिति यहां" कोड का मूल्यांकन किया जाता है।
- यदि इसके बजाय मान किसी
Just
मान के विरुद्ध मेल खाता है , तो दूसरी शाखा निष्पादित होती है। ध्यान दें कि कैसे मिलान खंड एक साथ मूल्य को एक Just
निर्माण के रूप में पहचानता है और इसके आंतरिक NotSoBroken
क्षेत्र को एक नाम (इस मामले में x
) में बांधता है । x
फिर सामान्य NotSoBroken
मूल्य की तरह उपयोग किया जा सकता है।
इसलिए, पैटर्न मिलान प्रकार की सुरक्षा को लागू करने के लिए एक शक्तिशाली सुविधा प्रदान करता है, क्योंकि ऑब्जेक्ट की संरचना को नियंत्रण के शाखा में अविभाज्य रूप से बांधा गया है।
मुझे आशा है कि यह एक स्पष्ट व्याख्या थी। अगर यह समझ में नहीं आता है, ग्रेट गुड के लिए लर्न यू ए हास्केल में कूदो ! , मैंने कभी पढ़ा है सबसे अच्छा ऑनलाइन भाषा ट्यूटोरियल में से एक। उम्मीद है कि आप इस भाषा में वही सुंदरता देखेंगे जो मैं करता हूं।