2016-04-24 7 views
8

मैं प्रोलॉग में adaptive parser लिखने का प्रयास कर रहा हूं: दूसरे शब्दों में, एक पार्सर जो रनटाइम पर अपने स्वयं के पार्सिंग नियमों को संशोधित कर सकता है।प्रोलॉग में अनुकूली पार्सिंग संभव है?

ऐसा करने में, मैं रनटाइम पर नए विधेय जनरेट करना होगा, लेकिन मुझे यकीन है कि अगर यह संभव हो सकता है नहीं कर रहा हूँ। इस तरह

generate_dcg_rule([A," is greater than ",B]). 

एक नया विधेय ... और फिर उत्पन्न करता है: यह एक विधेय है कि यह एक तरह एक सूची लेता लिखने के लिए संभव होगा?

expr(A," is greater than ",B) --> 
    symbol(A)," is greater than ",symbol(B). 

उत्तर

6

हाँ, जो आसानी से संभव है।

Prolog एक बहुत गतिशील भाषा है, और आप उदाहरण assertz/1 के लिए उपयोग कर रनटाइम पर मनमाने ढंग से खंड पर जोर कर सकते हैं।

आप अपने Prolog का कार्यकाल विस्तार तंत्र कि आम तौर पर ऐसा करने के लिए प्रयोग किया जाता है का उपयोग कर साधारण Prolog नियमों के DCG नियमों का विस्तार कर सकते हैं।

उदाहरण के लिए

, expand_term/2 का उपयोग कर:

 
?- expand_term((expr(A," is greater than ",B) --> 
    symbol(A)," is greater than ",symbol(B)), Clause). 
Clause = (expr(A, [' ', i, s, ' ', g, r, e|...], B, _G242, _G253):-symbol(A, _G242, _G264), _G264=[' ', i, s, ' ', g|...], symbol(B, _G275, _G253)). 

आप assertz/1 के साथ इस तरह खंड पर जोर कर सकते हैं:

 
?- expand_term((Head --> Body), Clause), assertz(Clause). 

ध्यान दें कि मैं इस उदाहरण में chars करने के लिए double_quotes सेट का उपयोग कर रहा हूँ, यानी, उपयोग:

 
:- set_prolog_flag(double_quotes, chars). 
अपने स्रोत में

फ़ाइलें। यह किसी भी मामले में एक अच्छा विचार है।

यह भी ध्यान दें कि मुझे लगता है कि आप अपने generate_dcg_rule/1 उदाहरण में दी गई सूचियों का अनुवाद करने के लिए पहले से ही   डीसीजी में अनुवाद करने का एक तरीका ढूंढ चुके हैं। इस अनुवाद के लिए, मैं list_dcg/2 जैसे भविष्यवाणी की अनुशंसा करता हूं जो ऐसी सूचियों और डीसीजी   नियमों के बीच संबंध का वर्णन करता है। लाभ स्पष्ट है: आप कर सकते हैं, उदाहरण के लिए परीक्षण इस तरह के संबंधों सहभागी और परीक्षण मामलों आदि अपने ठोस उदाहरण के लिए के साथ, एक खंड है कि इस संबंध को परिभाषित करता है के समान हो सकता है:

 
list_dcg([A,Ls,B], DCG) :- 
     Ls = "is greater than ", 
     DCG = (expr(A, Ls, B) --> symbol(A), Ls, symbol(B)). 

मैं करने के लिए इस सामान्यीकरण छोड़ अपने अभ्यास के रूप में अन्य उपयोग के मामलों। कुल में, एक ही रास्ता गतिशील रूप में इस तरह के खंड का दावा करने की इस प्रकार है:

 
?- list_dcg(List, DCG), expand_term(DCG, Clause), assertz(Clause). 

नोट कैसे हम इस तरह के उदाहरण में Prolog के homoiconic   प्रकृति से लाभ: Prolog   नियम और DCG   नियम Prolog के रूप में एक प्राकृतिक प्रतिनिधित्व   शर्तें, और हम उन्हें आसानी से लिख सकते हैं और उनके बारे में किसी भी अन्य शर्तों की तरह लक्ष्य भी ले सकते हैं।

+0

:

(A * A) * (b * b) = c^3 * 5 * 6 

कार्यक्रम के कार्यान्वयन यहाँ दिखाया गया है एक * निर्देश * और * अंतर्निहित भविष्यवाणी *, 'प्रारंभिक/1' निर्देश का उपयोग क्यों करें, जो ध्वज को सेट करने में देरी करेगा * उसके बाद * स्रोत फ़ाइल जिसमें संकलित और लोड किया गया है? –

+0

बहुत अच्छा मुद्दा, धन्यवाद! मैंने इसे तुरंत निर्देश का उपयोग करने के लिए बदल दिया है। – mat

2

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

यह एक संभव इनपुट है:

(A squared) times (b squared) equals c to the power of 3 times the product of 5 and 6 

और इस इसके उत्पादन है: के साथ `set_prolog_flag/2` जा रहा है

:- initialization(main). 
:- set_prolog_flag(double_quotes, chars). % This is for SWI 7+ to revert to the prior interpretation of quoted strings. 

%This is an adaptive parser for SWI-Prolog. 

main :- 
    %Type any kind of input here to see the output! The input must be compatible with the grammar that is defined below.   
    Input = "(A squared) times (b squared) equals c to the power of 3 times the product of 5 and 6", 

    iterated_translate(Input,Output), writeln(Input), writeln(Output), writeln('\n'), writeln('\n'). 

%The grammar is defined here. The variables must be uppercase letters. 
%The input in each translation rule is followed by its output. 
theList(TheList) :- 
      %You can easily extend this parser by adding more rules to this list. 
      TheList = 
      [['A to the power of B', 
       'A^B'], 
      %The next transformation is the final output of 'A to the power of B'. 
      ['A^B', 
       'A^B'], 
      ['A * B', 
       'A * B'], 
      ['the product of A and B', 
       'A times B'], 
      ['A squared', 
       'the product of A and A'], 
      ['A times B', 
       'A * B'], 
      ['A = B', 
       'A = B'], 
      ['A equals B', 'A = B']]. 
%This is the end of the grammar. The rest of the translator is implemented below. 

output_expr(Lang,[Input,[A,B]]) --> 
     { 
     theList(TheList), 
     list_to_output__(TheList,TheList1,[A,B]), 
     member([Input,Output], 
      TheList1) 
     }, 
     input_to_output_(Lang,Input,Output). 

atom_is_upper(N) :- 
    atom_chars(N, [L]), 
    char_type(L, upper). 

atom_is_var(Names_to_vars,Atom,Var) :- 
    atom(Atom),atom_is_upper(Atom),member([Atom,Var],Names_to_vars). 

list_to_output__([],[],_) :- true. 
list_to_output__([Start1|Rest1],[Start2|Rest2],Vars) :- 
    list_to_output_(Start1,Start2,Vars),list_to_output__(Rest1,Rest2,Vars). 

list_to_output_([A1_,B1_],[A2,B2],Vars) :- atomic_list_concat(A1,' ',A1_),atomic_list_concat(B1,' ',B1_),list_to_output(A1,A2,Vars),list_to_output(B1,B2,Vars). 

list_to_output([],[],_) :- true. 
list_to_output([Start1|Rest1],[Start2|Rest2],[A,B]) :- 
    (Start1='A'->Start2=A;Start1='B'-> Start2=B;Start1=Start2),list_to_output(Rest1,Rest2,[A,B]). 

list_to_grammar_(Lang,Start,Rest) --> 
    {(Start = [A])->(Rest = []->Start1 = expr(Lang,A);Start1 = parentheses_expr(Lang,A));atom_chars(Start,Start1)},Start1. 

list_to_grammar(Lang,[Start]) --> 
    list_to_grammar_(Lang,Start,[]). 

list_to_grammar(Lang,[Start|Rest]) --> 
    list_to_grammar_(Lang,Start,Rest),ws_,list_to_grammar(Lang,Rest). 

a_number([A,B]) --> 
    (a__number(A), ".", a__number(B)). 

a_number(A) --> 
    a__number(A). 

a__number([L|Ls]) --> digit(L), a__number_r(Ls). 
a__number_r([L|Ls]) --> digit(L), a__number_r(Ls). 
a__number_r([])  --> []. 
digit(Let)  --> [Let], { code_type(Let, digit) }. 

symbol([L|Ls]) --> letter(L), symbol_r(Ls). 
symbol_r([L|Ls]) --> letter(L), symbol_r(Ls). 
symbol_r([])  --> []. 
letter(Let)  --> [Let], { code_type(Let, alpha) }. 

ws --> "";((" ";"\n"),ws). 
ws_ --> (" ";"\n"),ws. 

input_to_output(Lang,A,B) --> 
    {Lang = input} -> 
     A; 
    {Lang=output} -> 
     B. 

input_to_output_(Lang,A,B) --> 
    {A_=list_to_grammar(Lang,A),B_=list_to_grammar(Lang,B)},input_to_output(Lang,A_,B_). 

parentheses_expr(Lang,["(",A,")"]) --> 
    ("(",(expr(Lang,A)),")"). 

parentheses_expr(_,symbol(A)) --> 
    symbol(A). 

parentheses_expr(_,a_number(A)) --> 
    a_number(A). 

expr(Lang,A) --> 
    parentheses_expr(Lang,A);output_expr(Lang,A). 

translate(Input1,Output1) :- 
    phrase(output_expr(input,Ls),Input1), 
    phrase(output_expr(output,Ls),Output1). 

iterated_translate(Input1, Output2) :- 
    %Keep translating until the input is the same as the output. 
    translate(Input1,Output1), 
    (Input1=Output1, Output1 = Output2;iterated_translate(Output1,Output2)). 
+0

ओह हाँ यह अच्छा है! 'Input_to_output // 3' में, आप 'input_to_output (इनपुट, ए, _) -> ए' और' input_to_output (आउटपुट, _, बी) -> दो खंडों का उपयोग करके, डीसीजी हेड में एकीकरण को खींच सकते हैं। बी। लाभ: अधिक सामान्य (अगर पहली तर्क अनइंस्टेन्टेड किया जाता है तो भी इसका उपयोग किया जा सकता है)! 'List_to_output/3' में, आप केवल 'हेड: - सच' के बजाय तथ्यों का उपयोग कर सकते हैं, यानी, बस 'हेड' लिखें। इसके अलावा, ऐसा लगता है कि यदि आप पहले 'वर्स' रखने के लिए तर्कों को पुन: व्यवस्थित करते हैं तो आप 'मैपलिस्ट/3' से लाभ उठा सकते हैं। फिर आप 'maplist (list_to_output (Vars), Ls0, Ls) कह सकते हैं और कोड को छोटा कर सकते हैं। इसे साझा करने के लिए आपको धन्यवाद! – mat

+0

@mat मैं इस पार्सर को बाएं-रिकर्सिव व्याकरण के साथ संगत बनाने की कोशिश कर रहा हूं। क्या यह आईएसओ प्रोलॉग में संभव होगा? –

+0

हां, यह निश्चित रूप से संभव है। ऐसा करने का एक तरीका बाएं-कारककरण नामक तकनीक का उपयोग करना है। इस तरह से मौजूदा व्याकरण को फिर से लिखना एक अच्छा अभ्यास है। एक अलग दृष्टिकोण टोकन की एक सूची के आसपास पारित करना है जो * अधिकतर * उपभोग किया जा सकता है, और प्रत्येक डीसीजी नियम को पहले से ही टोकन की संख्या को अंततः उपभोग करने की अनुमति देनी चाहिए। एक साधारण फिक्सपॉइंट एल्गोरिदम का उपयोग करके, आप इन नियमों को प्रत्येक नियम के "सामने" खींच सकते हैं, और नियम लागू होने के लिए पर्याप्त टोकन होने पर अग्रिम जांच कर सकते हैं। आप निश्चित रूप से सही रास्ते पर हैं, प्रोलॉग में यह सब करना बहुत अच्छा है! – mat