Parsing Prolog中上下文无关语法(CFG)的序列生成器可能使用DCG

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中编写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]


有了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我同意,但在这种情况下它实际上取决于谓词将如何使用。如果您每次都计算不同的语法,是的。如果您只更改起始顺序,断言没有错。