我想在Prolog中编写gen(G,S)来为给定的语法G生成有效的序列S,其中G是格式语法([非终结者列表],[终端列表],[列表]规则],[起始顺序])。规则采用格式规则(nt,[x]),其中x可以是任何非终结符和/或终端列表。
e.g。 gen(语法([a,b],[t,q,y,z],[规则(a,[t]),规则(a,[z]),规则(b,[y]),规则( 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]。
在CFG上为Prolog提供了所有信息(已经尝试了2天),我可以找出至少一种方法来做到这一点,使用内置的 - >和短语/ 2或从头开始,但没有运气。 (从未发布过SO b4&我是初学者,所以如果这个Q不合适我很抱歉。)
答案 0 :(得分:1)
无需诉诸特殊的非逻辑谓词。这就是诀窍:
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).
答案 1 :(得分:0)
这是一个至少应该指向正确方向的解决方案。它是不同的,因为我直接将终端,非终端和规则定义为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].
要将其转换为您要查找的谓词,请考虑以下事项:
可以使用member/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
。
我相信还有另一种方式。