Prolog Language
आधुनिक प्रस्तावना का उपयोग करना
खोज…
परिचय
कई आधुनिक प्रोलॉग सिस्टम निरंतर विकास में हैं और उन्होंने भाषा की क्लासिक कमियों को दूर करने के लिए नई सुविधाओं को जोड़ा है। दुर्भाग्य से, कई प्रोलॉग पाठ्यपुस्तकें और यहां तक कि शिक्षण पाठ्यक्रम अभी भी केवल पुराने प्रोलॉग का परिचय देते हैं। इस विषय को स्पष्ट करने का इरादा है कि कैसे आधुनिक प्रोलोग ने कुछ समस्याओं को दूर किया है और बल्कि पुराने प्रोलॉग में प्रकट होने वाले क्रुफ़्टी सिंटैक्स और अभी भी पेश किए जा रहे हैं।
पूर्णांक अंकगणित के लिए सीएलपी (एफडी)
परंपरागत रूप से Prolog का उपयोग कर अंकगणित प्रदर्शन किया is
और =:=
ऑपरेटरों। हालाँकि, कई वर्तमान प्रस्ताव पूर्णांक अंकगणित के लिए एक क्लीनर विकल्प के रूप में CLP (FD) (परिमित तर्क प्रोग्रामिंग पर परिमित डोमेन) प्रदान करते हैं। सीएलपी (एफडी) उन अवरोधों को संग्रहीत करने पर आधारित है जो पूर्णांक मान पर लागू होते हैं और उन सभी को स्मृति में एक साथ जोड़ते हैं।
सीएलपी (एफडी) अधिकांश प्रोलॉग्स में एक विस्तार है जो इसका समर्थन करता है, इसलिए इसे स्पष्ट रूप से लोड किया जाना चाहिए। एक बार जब यह लोड हो जाता है, तो #=
सिंटैक्स दोनों is
स्थान ले सकता is
और =:=
। उदाहरण के लिए, SWI- प्रोलॉग में:
?- X is 2+2.
X = 4.
?- use_module(library(clpfd)).
?- X #= 2+2.
X = 4.
विपरीत is
, #=
सरल समीकरणों को हल करने और दोनों दिशाओं में सक्षम यूनिफाई है:
?- 4 is 2+X.
ERROR: is/2: Arguments are not sufficiently instantiated
?- 4 #= 2+X.
X = 2.
सीएलपी (एफडी) अपने स्वयं के जनरेटर सिंटैक्स प्रदान करता है।
?- between(1,100,X).
X = 1;
X = 2;
X = 3...
?- X in 1..100.
X in 1..100.
ध्यान दें कि जनरेटर वास्तव में नहीं चलता है: केवल सीमा की सीमा को संग्रहीत किया जाता है, बाद की बाधाओं के लिए इसके साथ संयुक्त होने के लिए तैयार है। जनरेटर को विधेय label
का उपयोग करके चलाने के लिए मजबूर किया जा सकता है (और बल बल की कमी):
?- X in 1..100, label([X]).
X = 1;
X = 2;
X = 3..
सीएलपी का उपयोग करने से ब्रूट बल के मामलों में कुछ बुद्धिमान कमी हो सकती है। उदाहरण के लिए, पुरानी शैली के पूर्णांक अंकगणितीय का उपयोग करना:
?- trace.
?- between(1,10,X), Y is X+5, Y>10.
...
Exit: (8) 6 is 1+5 ? creep
Call: (8) 6 > 10 ? creep
...
X = 6, Y = 11; ...
प्रोलॉग अभी भी 1-5 मूल्यों के माध्यम से लूप करता है, भले ही यह दिए गए शर्तों से गणितीय रूप से सिद्ध हो कि ये मान उपयोगी नहीं हो सकते। सीएलपी (एफडी) का उपयोग करना:
?- X in 1..10, Y #= X+5, Y #> 10.
X is 6..10,
X+5 #= Y,
Y is 11..15.
सीएलपी (एफडी) तुरंत गणित करता है और उपलब्ध श्रेणियों को पूरा करता है। label([Y])
जोड़ने से X केवल उपयोगी मानों के माध्यम से लूप हो जाएगा। 6..10 इस खिलौने के उदाहरण में, यह प्रदर्शन को नहीं बढ़ाता है क्योंकि 1-10 जैसी छोटी रेंज के साथ, बीजगणित प्रसंस्करण में उतना ही समय लगता है जितना कि लूप ने किया होगा; लेकिन जब संख्याओं की एक बड़ी श्रृंखला को संसाधित किया जा रहा है तो यह गणना के समय को महत्वपूर्ण रूप से कम कर सकता है।
CLP (FD) के लिए समर्थन Prologs के बीच परिवर्तनशील है। सीएलपी (एफडी) का सबसे अच्छा विकास SICStus Prolog में है, जो वाणिज्यिक और महंगा है। SWI- प्रोलॉग और अन्य खुले प्रोलॉग्स में अक्सर कुछ कार्यान्वयन होता है। विजुअल प्रोलॉग में अपने मानक पुस्तकालय में सीएलपी (एफडी) शामिल नहीं है, हालांकि इसके लिए विस्तार पुस्तकालय उपलब्ध हैं।
विफलता-चालित छोरों के बजाय फोर्ल
कुछ "क्लासिक" प्रोलॉग पाठ्यपुस्तकें अभी भी भ्रामक और त्रुटि-प्रवण विफलता-चालित लूप सिंटैक्स का उपयोग करती fail
जहां एक fail
निर्माण का उपयोग जनरेटर के प्रत्येक मूल्य पर एक लक्ष्य को लागू करने के लिए पीछे हटने के लिए किया जाता है। उदाहरण के लिए, दिए गए सीमा तक सभी नंबरों को प्रिंट करने के लिए:
fdl(X) :- between(1,X,Y), print(Y), fail.
fdl(_).
आधुनिक प्रोलॉग्स के विशाल बहुमत को अब इस सिंटैक्स की आवश्यकता नहीं है, इसके बजाय इसे संबोधित करने के लिए एक उच्च आदेश प्रदान करते हैं।
nicer(X) :- forall(between(1,X,Y), print(Y)).
न केवल पढ़ने में यह बहुत आसान है, लेकिन अगर कोई ऐसा लक्ष्य जो प्रिंट के स्थान पर विफल हो जाता है, तो उसकी विफलता का सही तरीके से पता लगाया जाएगा और उसे पारित किया जाएगा - जबकि विफलता से प्रेरित लूप में लक्ष्यों की विफलता को मजबूर विफलता के साथ भ्रमित किया जाता है वह पाश चलाती है।
विजुअल प्रोलॉग में इन छोरों के लिए एक कस्टम सिंटैक्टिक शुगर है, जो फ़ंक्शन की भविष्यवाणी के साथ संयुक्त है (नीचे देखें):
vploop(X) :- foreach Y = std::fromTo(1,X) do
console::write(X)
end foreach.
हालांकि पाश के लिए एक अनिवार्य की तरह इस दिखता है, यह अभी भी Prolog नियम इस प्रकार है: विशेष रूप से, foreach से प्रत्येक यात्रा का अपना गुंजाइश है।
कार्य-शैली की भविष्यवाणी
परंपरागत रूप से प्रोलॉग में, "फ़ंक्शंस" (एक आउटपुट और बाउंड इनपुट के साथ) नियमित रूप से लिखे गए थे:
mangle(X,Y) :- Y is (X*5)+2.
यह कठिनाई पैदा कर सकता है कि अगर एक फ़ंक्शन-स्टाइल विधेय को कई बार कहा जाता है, तो अस्थायी श्रृंखला को "डेज़ी चेन" करना आवश्यक है।
multimangle(X,Y) :- mangle(X,A), mangle(A,B), mangle(B,Y).
अधिकांश प्रोलॉग्स में, इसके स्थान पर उपयोग करने के लिए एक वैकल्पिक इन्फिक्स ऑपरेटर लिखकर इससे बचना संभव is
जो वैकल्पिक फ़ंक्शन सहित अभिव्यक्तियों का विस्तार करता है।
% Define the new infix operator
:- op(900, xfy, <-).
% Define our function in terms of the infix operator - note the cut to avoid
% the choice falling through
R <- mangle(X) :- R is (X*5)+2, !.
% To make the new operator compatible with is..
R <- X :-
compound(X), % If the input is a compound/function
X =.. [OP, X2, X3], % Deconstruct it
R2 <- X2, % Recurse to evaluate the arguments
R3 <- X3,
Expr =.. [OP, R2, R3], % Rebuild a compound with the evaluated arguments
R is Expr, % And send it to is
!.
R <- X :- R is X, !. % If it's not a compound, just use is directly
अब हम लिख सकते हैं:
multimangle(X,Y) :- X <- mangle(mangle(mangle(Y))).
हालांकि, कुछ आधुनिक प्रस्ताव आगे बढ़ते हैं और इस प्रकार के विधेय के लिए एक कस्टम सिंटैक्स प्रदान करते हैं। उदाहरण के लिए, दृश्य प्रस्ताव में:
mangle(X) = Y :- Y = ((X*5)+2).
multimangle(X,Y) :- Y = mangle(mangle(mangle(X))).
ध्यान दें कि <-
ऑपरेटर और कार्यात्मक-शैली उपर्युक्त अभी भी संबंधों के रूप में व्यवहार करती है - उनके लिए यह पसंद है कि उनके पास पसंद अंक हों और कई एकीकरण करें। पहले उदाहरण में, हम कटौती का उपयोग करके इसे रोकते हैं। विज़ुअल प्रोलॉग में, संबंधों के लिए कार्यात्मक वाक्यविन्यास का उपयोग करना सामान्य है और पसंद अंक सामान्य तरीके से बनाए जाते हैं - उदाहरण के लिए, लक्ष्य X = (std::fromTo(1,10))*10
बाइंडिंग के साथ सफल होता है X = 10 , एक्स = 20, एक्स = 30, एक्स = 40, आदि।
प्रवाह / मोड घोषणाएं
प्रोलॉग में प्रोग्रामिंग जब यह संभव नहीं है, या वांछनीय है, तो विधेय बनाने के लिए जो मापदंडों के हर संभव संयोजन के लिए एकजुट होते हैं। उदाहरण के लिए, between(X,Y,Z)
का विधेय between(X,Y,Z)
जो यह व्यक्त करता है कि Z, X और Y के बीच संख्यात्मक रूप से है। यह उन मामलों में आसानी से लागू होता है, जहां X, Y और Z सभी बद्ध हैं (या तो Z, X और Y के बीच है) यह नहीं है), या जहां X और Y बंधे हैं और Z मुफ़्त है (Z, X और Y के बीच की सभी संख्याओं के साथ एकीकृत होता है, या यदि Y <X) के लिए विधेय विफल रहता है; लेकिन अन्य मामलों में, जैसे कि X और Z बाध्य हैं और Y स्वतंत्र हैं, संभावित रूप से एकीकरण की एक अनंत संख्या है। हालांकि इसे लागू किया जा सकता है, यह आमतौर पर नहीं होगा।
फ्लो डिक्लेरेशन या मोड डिक्लेरेशन एक स्पष्ट विवरण देते हैं कि बाध्य मापदंडों के विभिन्न संयोजनों के साथ कॉल करने पर कैसे व्यवहार करता है। between
के मामले में, घोषणा होगी:
%! between(+X,+Y,+Z) is semidet.
%! between(+X,+Y,-Z) is nondet.
प्रत्येक पंक्ति विधेय के लिए एक संभावित कॉलिंग पैटर्न निर्दिष्ट करती है। प्रत्येक तर्क को उन मामलों को इंगित करने के लिए +
साथ सजाया गया है जहां यह बाध्य है, या -
उन मामलों को इंगित करने के लिए जहां यह नहीं है (अधिक जटिल प्रकारों जैसे ट्यूपल्स या सूची के लिए उपलब्ध अन्य सजावट भी उपलब्ध हैं जो आंशिक रूप से बाध्य हो सकते हैं)। उसके बाद का कीवर्ड उस मामले में विधेय के व्यवहार को इंगित करता है, और इनमें से एक हो सकता है:
- अगर कोई विकल्प बिंदु के साथ विधेय हमेशा सफल होता है तो
det
लें। उदाहरण के लिएadd(+X,+Y,-Z)
हैdet
क्योंकि दिए गए दो नंबरों एक्स जोड़ने और वाई हमेशा वास्तव में एक ही जवाब होगा। -
semidet
अगर विधेय या तो सफल होता है या विफल रहता है, और कोई चारा नहीं बिंदु के साथ। जैसा कि ऊपर,between(+X,+Y,+Z)
हैsemidet
क्योंकि जेड एक्स और वाई के बीच या तो है या यह नहीं है। -
multi
यदि विधेय हमेशा सफल होता है, लेकिन पसंद अंक हो सकता है (लेकिन यह भी नहीं हो सकता है)। उदाहरण के लिए,factor(+X,-Y)
multi
होगा क्योंकि एक संख्या में हमेशा कम से कम एक कारक होता है - स्वयं - लेकिन अधिक हो सकता है। -
nondet
अगर विधेय पसंद अंक के साथ सफल हो सकता है, या विफल हो सकता है। उदाहरण के लिए,between(+X,+Y,-Z)
nondet
क्योंकि X और Y के बीच संख्याओं के लिए Z के कई संभावित एकीकरण हो सकते हैं, या यदि Y <X तो उनके बीच कोई संख्या नहीं है और विधेय विफल रहता है।
फ्लो / मोड घोषणाओं को तर्क लेबलिंग के साथ भी जोड़ा जा सकता है ताकि स्पष्ट किया जा सके कि शब्दों का क्या अर्थ है या टाइपिंग के साथ। उदाहरण के लिए, between(+From:Int, +To:Int, +Mid:Int) is semidet
।
शुद्ध प्रोलॉग्स में, प्रवाह और मोड घोषणाएं वैकल्पिक हैं और केवल प्रलेखन पीढ़ी के लिए उपयोग की जाती हैं, लेकिन वे प्रोग्रामर को तत्काल त्रुटियों के कारण की पहचान करने में मदद करने के लिए बेहद उपयोगी हो सकते हैं।
बुध में, प्रवाह और मोड घोषणाएं (और प्रकार) अनिवार्य हैं और संकलक द्वारा मान्य हैं। सिंटैक्स का उपयोग ऊपर है।
विजुअल प्रोलॉग में, प्रवाह और मोड घोषणाएं और प्रकार भी अनिवार्य हैं और वाक्यविन्यास अलग है। उपरोक्त घोषणा इस प्रकार लिखी जाएगी:
between : (int From, int To, int Mid) determ (i,i,i) nondeterm (i,i,o).
अर्थ उपरोक्त के समान है, लेकिन अंतर के साथ:
- प्रवाह / मोड घोषणाओं को प्रकार की घोषणाओं से अलग किया जाता है (क्योंकि यह माना जाता है कि एक एकल विधेय के लिए प्रवाह / मोड प्रकार ओवरलोडिंग के साथ भिन्न नहीं होगा);
-
i
औरo
का उपयोग+
और-
लिए किया जाता है और ऑर्डर के आधार पर मापदंडों के साथ मिलान किया जाता है; - उपयोग की जाने वाली शर्तें अलग हैं।
det
हो जाता हैprocedure
,semidet
हो जाता हैdeterm
, औरnondet
हो जाता हैnondeterm
(multi
अब भी हैmulti
)।