ओओपी दुनिया में साइड इफेक्ट्स, अप्रतिबंधित विरासत और nullहर प्रकार के सदस्य होने के कारण एक प्रमाण बहुत कठिन है । अधिकांश प्रमाण एक प्रेरण सिद्धांत पर भरोसा करते हैं कि यह दिखाने के लिए कि आपने हर संभावना को कवर किया है, और उन सभी चीजों में से 3 साबित करने के लिए कठिन बनाते हैं।
मान लीजिए कि हम द्विआधारी पेड़ लगा रहे हैं जिसमें पूर्णांक मान शामिल हैं (सिंटैक्स को सरल रखने के लिए, मैं इसमें सामान्य प्रोग्रामिंग नहीं लाऊंगा, हालांकि यह कुछ भी नहीं बदलेगा।) मानक एमएल में, मैं इसे परिभाषित करूंगा। इस:
datatype tree = Empty | Node of (tree * int * tree)
यह एक नए प्रकार का परिचय देता है, treeजिसका मान बिल्कुल दो किस्मों (या कक्षाओं में आ सकता है, एक वर्ग की ओओपी अवधारणा से भ्रमित नहीं होना) - एक Emptyमूल्य जो कोई जानकारी नहीं देता है, और वे Nodeमूल्य जो 3-ट्यूपल ले जाते हैं जिनका पहला और अंतिम तत्व हैं treeऔर जिनका मध्य तत्व ए है int। OOP में इस घोषणा के लिए निकटतम सन्निकटन इस तरह दिखेगा:
public class Tree {
private Tree() {} // Prevent external subclassing
public static final class Empty extends Tree {}
public static final class Node extends Tree {
public final Tree leftChild;
public final int value;
public final Tree rightChild;
public Node(Tree leftChild, int value, Tree rightChild) {
this.leftChild = leftChild;
this.value = value;
this.rightChild = rightChild;
}
}
}
कैवेट के साथ कि प्रकार ट्री के चर कभी नहीं हो सकते null।
अब चलो पेड़ की ऊंचाई (या गहराई) की गणना करने के लिए एक फ़ंक्शन लिखते हैं, और मान लेते हैं कि हमारे पास एक ऐसे maxफ़ंक्शन की पहुंच है जो दो साल के बड़े रिटर्न देता है:
fun height(Empty) =
0
| height(Node (leftChild, value, rightChild)) =
1 + max( height(leftChild), height(rightChild) )
हमने heightफ़ंक्शन को मामलों द्वारा परिभाषित किया है - Emptyपेड़ों के लिए एक परिभाषा है और Nodeपेड़ों के लिए एक परिभाषा है । कंपाइलर जानता है कि पेड़ों के कितने वर्ग मौजूद हैं और यदि आप दोनों मामलों को परिभाषित नहीं करते हैं तो चेतावनी जारी करेंगे। अभिव्यक्ति Node (leftChild, value, rightChild)समारोह हस्ताक्षर में चर के 3-टपल के मूल्यों बांधता है leftChild, valueऔर rightChildक्रमशः तो हम समारोह परिभाषा उन्हें देख सकते हैं। यह एक ओओपी भाषा में इस तरह से स्थानीय चर घोषित करने के समान है:
Tree leftChild = tuple.getFirst();
int value = tuple.getSecond();
Tree rightChild = tuple.getThird();
हम कैसे साबित कर सकते हैं कि हमने heightसही तरीके से लागू किया है? हम स्ट्रक्चरल इंडक्शन का उपयोग कर सकते हैं , जिसमें निम्न शामिल हैं: 1. साबित करें कि heightहमारे treeप्रकार के बेस केस (एस) में सही है ( Empty2) मान लें कि पुनरावर्ती कॉल heightसही हैं, तो साबित करें कि heightगैर-आधार मामले के लिए सही है ) (जब पेड़ वास्तव में है Node)।
चरण 1 के लिए, हम देख सकते हैं कि फ़ंक्शन हमेशा 0 देता है जब तर्क एक Emptyपेड़ है। यह एक पेड़ की ऊंचाई की परिभाषा से सही है।
चरण 2 के लिए, फ़ंक्शन वापस लौटता है 1 + max( height(leftChild), height(rightChild) )। यह मानते हुए कि पुनरावर्ती कॉल वास्तव में बच्चों की ऊंचाई को वापस करते हैं, हम देख सकते हैं कि यह भी सही है।
और वह प्रमाण पूरा करता है। चरण 1 और 2 ने सभी संभावनाओं को मिला दिया। ध्यान दें, हालांकि, हमारे पास कोई उत्परिवर्तन, कोई नल नहीं है, और बिल्कुल दो प्रकार के पेड़ हैं। उन तीन स्थितियों को हटा दें और यदि अव्यवहारिक नहीं है, तो सबूत जल्दी से अधिक जटिल हो जाता है।
संपादित करें: चूंकि यह उत्तर शीर्ष पर पहुंच गया है, इसलिए मैं एक प्रमाण के कम तुच्छ उदाहरण जोड़ना चाहता हूं और संरचनात्मक प्रेरण को थोड़ा और अच्छी तरह से कवर करना चाहिए। ऊपर हमने साबित कर दिया कि अगर heightरिटर्न मिलता है , तो उसका रिटर्न वैल्यू सही है। हमने साबित नहीं किया है कि यह हमेशा एक मूल्य देता है, हालांकि। हम यह साबित करने के लिए संरचनात्मक प्रेरण का उपयोग कर सकते हैं, (या किसी अन्य संपत्ति।) फिर से, चरण 2 के दौरान, हमें पुनरावर्ती कॉलों की संपत्ति धारण करने की अनुमति है जब तक कि पुनरावर्ती कॉल सभी सीधे बच्चे पर संचालित होते हैं। पेड़।
एक फ़ंक्शन दो स्थितियों में एक मूल्य वापस करने में विफल हो सकता है: यदि यह एक अपवाद फेंकता है, और यदि यह हमेशा के लिए बंद हो जाता है। पहले यह साबित करते हैं कि यदि कोई अपवाद नहीं फेंका जाता है, तो कार्य समाप्त हो जाता है:
साबित करें कि (यदि कोई अपवाद नहीं फेंका जाता है) फ़ंक्शन आधार मामलों के लिए समाप्त हो जाता है ( Empty)। चूंकि हम बिना शर्त 0 वापस करते हैं, इसलिए यह समाप्त हो जाता है।
साबित करें कि फ़ंक्शन गैर-बेस मामलों ( Node) में समाप्त होता है । वहाँ तीन फ़ंक्शन कॉल यहाँ है: +, max, और height। हम यह जानते हैं +और maxक्योंकि वे भाषा के मानक पुस्तकालय की कर रहे हैं हिस्सा समाप्त कर देंगे और वे जिस तरह से है कि परिभाषित कर रहे हैं। जैसा कि पहले उल्लेख किया गया है, हमें यह मानने की अनुमति है कि हम जिस संपत्ति को साबित करने की कोशिश कर रहे हैं, वह पुनरावर्ती कॉलों पर तब तक सही है जब तक वे तत्काल उपप्रकारों पर काम करते हैं, इसलिए कॉल heightभी समाप्त हो जाते हैं।
वह प्रमाण को समाप्त करता है। ध्यान दें कि आप एक इकाई परीक्षण के साथ समाप्ति साबित नहीं कर पाएंगे। अब जो कुछ बचा है वह heightयह दिखाना है कि अपवाद नहीं फेंकता है।
- साबित करें कि
heightआधार मामले पर अपवाद नहीं फेंकते हैं ( Empty)। रिटर्निंग 0 एक अपवाद नहीं फेंक सकता है, इसलिए हम कर रहे हैं।
- साबित करें कि
heightगैर-आधार मामले पर अपवाद को फेंकना नहीं है ( Node)। एक बार फिर से मान लें कि हम जानते हैं +और maxअपवाद नहीं फेंकते हैं। और संरचनात्मक प्रेरण हमें अनुमान लगाने की अनुमति देता है कि पुनरावर्ती कॉल या तो नहीं फेंकेंगे (क्योंकि पेड़ के तत्काल बच्चों पर काम करते हैं।) लेकिन रुको! यह कार्य पुनरावर्ती है, लेकिन पुनरावर्ती नहीं है । हम ढेर को उड़ा सकते हैं! हमारे प्रयास के सबूत ने बग को उजागर किया है। हम पूंछ पुनरावर्ती होने के लिए इसे बदलकरheight ठीक कर सकते हैं ।
मुझे उम्मीद है कि यह सबूत दिखाता है कि डरावना या जटिल नहीं होना चाहिए। वास्तव में, जब भी आप कोड लिखते हैं, तो आपने अनौपचारिक रूप से अपने सिर में एक सबूत का निर्माण किया है (अन्यथा, आप आश्वस्त नहीं होंगे कि आपने फ़ंक्शन को लागू किया है।) अशक्त, अनावश्यक उत्परिवर्तन और अप्रतिबंधित विरासत से बचकर आप अपने अंतर्ज्ञान को साबित कर सकते हैं। सही आसानी से। ये प्रतिबंध उतने कठोर नहीं हैं जितना आप सोच सकते हैं:
null एक भाषा दोष है और इसे दूर करना बिना शर्त अच्छा है।
- उत्परिवर्तन कभी-कभी अपरिहार्य और आवश्यक होता है, लेकिन यह बहुत बार आपको सोचने की तुलना में बहुत कम की आवश्यकता होती है - खासकर जब आपके पास लगातार डेटा संरचनाएं होती हैं।
- कक्षाओं की एक सीमित संख्या (कार्यात्मक अर्थों में) / उपवर्गों (ओओपी अर्थों में) बनाम असीमित संख्या में होने के कारण, यह एक एकल उत्तर के लिए बहुत बड़ा विषय है । यह कहने के लिए पर्याप्त है कि वहाँ एक डिजाइन व्यापार है - विस्तार की लचीलापन बनाम शुद्धता की उपयोगिता।