Parsing Prolog中上下文无关语法(CFG)的序列生成器可能使用DCG
我想在Prolog中编写gen(G,S)来为给定的语法G生成一个有效的序列S,其中G的格式是语法([非终端列表],[终端列表],[规则列表],[起始序列])。规则采用格式规则(nt,[x]),其中x可以是任何非终端和/或终端列表 e、 g。 gen(语法([a,b],[t,q,y,z],[rule(a[t]),rule(a[z]),rule(b[y]),rule(b[a,q]),[a,b]),X) 返回: X=[t,y]。 X=[t,t,q]。 X=[t,z,q]。 X=[z,y]。 X=[z,t,q]。 X=[z,z,q]Parsing Prolog中上下文无关语法(CFG)的序列生成器可能使用DCG,parsing,prolog,sequence,grammar,dcg,Parsing,Prolog,Sequence,Grammar,Dcg,我想在Prolog中编写gen(G,S)来为给定的语法G生成一个有效的序列S,其中G的格式是语法([非终端列表],[终端列表],[规则列表],[起始序列])。规则采用格式规则(nt,[x]),其中x可以是任何非终端和/或终端列表 e、 g。 gen(语法([a,b],[t,q,y,z],[rule(a[t]),rule(a[z]),rule(b[y]),rule(b[a,q]),[a,b]),X) 返回: X=[t,y]。 X=[t,t,q]。 X=[t,z,q]。 X=[z,y]。 X=[z,
有了Prolog的CFG上的所有信息(已经尝试了2天),I s/b能够想出至少一种方法来实现这一点,要么使用内置-->和短语/2,要么从头开始,但运气不好。(从未在SO b4上发布过&我是一个初学者,如果这个问题不合适,我深表歉意。)这里有一个解决方案,至少应该为您指明正确的方向。这是不同的,因为我直接将终端、非终端和规则定义为Prolog事实:
nt(a). nt(b).
t(t). t(q). t(y). t(z).
rule(a, [t]).
rule(a, [z]).
rule(b, [y]).
rule(b, [a,q]).
从这里开始,您需要一个谓词,它接受一个起始序列并应用规则:
gen([], []).
gen([A|As], S) :-
( t(A)
-> S = [A|Ts]
; nt(A)
-> rule(A, Bs),
gen(Bs, Cs),
append(Cs, Ts, S)
),
gen(As, Ts).
如果符号是端子,则它属于结束序列。如果是非终端,则对其应用规则,然后对结果应用gen/2
。我假设您知道Prolog中的递归是如何工作的,if-else,以及append/3
的作用
?- [gen].
% gen compiled 0.00 sec, 13 clauses
true.
?- gen([a,b], S).
S = [t, y] ;
S = [t, t, q] ;
S = [t, z, q] ;
S = [z, y] ;
S = [z, t, q] ;
S = [z, z, q].
将此转换为你要查找的谓词,考虑以下内容:
可以使用成员/2
枚举列表:
?- member(NT, [a,b]).
NT = a ;
NT = b.
您可以使用assertz/1
将事实和规则添加到数据库中:
?- assertz(t(t)), assertz(t(q)). % etc
您可以使用forall/2
来避免编写显式循环:
?- forall(member(R, Rules), assertz(R)).
如果需要,您可以直接在列表上使用member/2
我相信还有另一种方法。这里有一个解决方案,至少应该为您指明正确的方向。这是不同的,因为我直接将终端、非终端和规则定义为Prolog事实:
nt(a). nt(b).
t(t). t(q). t(y). t(z).
rule(a, [t]).
rule(a, [z]).
rule(b, [y]).
rule(b, [a,q]).
从这里开始,您需要一个谓词,它接受一个起始序列并应用规则:
gen([], []).
gen([A|As], S) :-
( t(A)
-> S = [A|Ts]
; nt(A)
-> rule(A, Bs),
gen(Bs, Cs),
append(Cs, Ts, S)
),
gen(As, Ts).
如果符号是端子,则它属于结束序列。如果是非终端,则对其应用规则,然后对结果应用gen/2
。我假设您知道Prolog中的递归是如何工作的,if-else,以及append/3
的作用
?- [gen].
% gen compiled 0.00 sec, 13 clauses
true.
?- gen([a,b], S).
S = [t, y] ;
S = [t, t, q] ;
S = [t, z, q] ;
S = [z, y] ;
S = [z, t, q] ;
S = [z, z, q].
将此转换为你要查找的谓词,考虑以下内容:
可以使用成员/2
枚举列表:
?- member(NT, [a,b]).
NT = a ;
NT = b.
您可以使用assertz/1
将事实和规则添加到数据库中:
?- assertz(t(t)), assertz(t(q)). % etc
您可以使用forall/2
来避免编写显式循环:
?- forall(member(R, Rules), assertz(R)).
如果需要,您可以直接在列表上使用member/2
我相信还有另一种方法。没有必要求助于特殊的非逻辑谓词。这就是诀窍:
gen(grammar(_NTE, _TE, _Rules, []), []).
gen(grammar(NTE, TE, Rules, [H|T]), X) :-
member(H, NTE),
member(rule(H, Res), Rules),
append(Res, T, NewT),
gen(grammar(NTE, TE, Rules, NewT), X).
gen(grammar(NTE, TE, Rules, [H|T]), [H|X2]) :-
member(H, TE),
gen(grammar(NTE, TE, Rules, T), X2).
没有必要求助于特殊的非逻辑谓词。这就是诀窍:
gen(grammar(_NTE, _TE, _Rules, []), []).
gen(grammar(NTE, TE, Rules, [H|T]), X) :-
member(H, NTE),
member(rule(H, Res), Rules),
append(Res, T, NewT),
gen(grammar(NTE, TE, Rules, NewT), X).
gen(grammar(NTE, TE, Rules, [H|T]), [H|X2]) :-
member(H, TE),
gen(grammar(NTE, TE, Rules, T), X2).
你有没有任何你试过的代码可以展示出来?我好像写不出来。我从来没有被这样难倒过。我可以使用-->和短语/2为示例语法生成一个序列,但没有通用性,因此毫无帮助。:'(您是否有任何您尝试过的代码可以展示?我似乎无法写出1个loc。我从来没有像b4这样被难倒过。我可以使用-->和短语/2为示例语法生成序列,但没有通用代码,因此根本没有帮助。:)(通常应避免使用assert和assertz。@ChristianF我同意,但在这种情况下,这实际上取决于谓词的使用方式。如果每次都计算不同的语法,则是的。如果只更改起始顺序,则断言没有错。通常应避免使用assert和assertz。@ChristianF我同意,但在这种情况下它实际上取决于谓词将如何使用。如果您每次都计算不同的语法,是的。如果您只更改起始顺序,断言没有错。