首页 > 解决方案 > 在序言中生成诗句的问题

问题描述

给定 Prolog 中的一个问题,
在一种失落的世界语言中,一首诗可以有任意数量的诗句,每节都采用以下形式:

ABBC
DEEC
FFG
HIIC

其中相同的字母代表押韵的词。例如,
anun kura tama su
unuri bimo co kuru
sonen ariten sicom
kana te shime xanadu。

我们必须为给定的诗句生成一首诗。

我的代码

norhyme(X):- X="anun";X="unuri";X="sicom";X="kana".
pairrhyme(X,Y):-X="kura",Y="tama";
                X="tama",Y="Kura";
                X="bimo",Y="co";
                X="co",Y="bimo";
                X="sonen",Y="ariten";
                X="ariten",Y="sonen";
                X="te",Y="shime";
                X="shime",Y="te";
                X="su",Y="kuru";
                X="kuru",Y="su";
                X="kuru",Y="shanadu";
                X="shanadu",Y="kuru";
                X="su",Y="xanadu",
                X="xanadu",Y="su".
triplerhyme(X,Y,Z):-X="su",Y="kuru",Z="xanadu".

generatepoem(0).
generatepoem(Y):- norhyme(A),pairrhyme(B,C),triplerhyme(D,E,F),
                  write(A),write(' '),write(B),write(' '),write(C),write(' '),write(D),nl,
                  norhyme(G),pairrhyme(H,I),
                  write(G),write(' '),write(H),write(' '),write(I),write(' '),write(E),nl,
                  pairrhyme(J,K),norhyme(L),
                  write(J),write(' '),write(K),write(' '),write(L),nl,
                  norhyme(M),pairrhyme(N,O),
                  write(M),write(' '),write(N),write(' '),write(O),write(' '),write(F), nl,
                  Y1 is Y-1,generatepoem(Y1).

理想情况下,输出应该是

anun kura tama su
anun kura tama kuru
kura tama anun
anun kura tama xanadu

//as well as

anun kura tama su
anun tama kura kuru
bimo co anun
anun kuru su xanadu

//and all other possible combinations

但是我没有得到所有的组合,我的程序进入了一个无限循环。问题是什么??

欲了解更多信息,请在下面发表评论。

标签: prolog

解决方案


这是一个更时尚的正确版本:

norhyme(anun).
norhyme(unuri).
norhyme(sicom).
norhyme(kana).

pairrhyme_one_way(kura,tama).
pairrhyme_one_way(bimo,co).
pairrhyme_one_way(sonen,ariten).
pairrhyme_one_way(te,shime).
pairrhyme_one_way(su,kuru).
pairrhyme_one_way(kuru,shanadu).
pairrhyme_one_way(su,xanadu).

pairrhyme(X,Y) :- pairrhyme_one_way(X,Y).
pairrhyme(X,Y) :- pairrhyme_one_way(Y,X).

triplerhyme(su,kuru,xanadu).

generatepoem(0).
generatepoem(Y):- 
   Y > 0,
   norhyme(A),
   pairrhyme(B,C),
   triplerhyme(D,E,F),
   format("~a ~a ~a ~a~n",[A,B,C,D]),
   norhyme(G),
   pairrhyme(H,I),
   format("~a ~a ~a ~a~n",[G,H,I,E]),
   pairrhyme(J,K),
   norhyme(L),
   format("~a ~a ~a~n",[J,K,L]),
   norhyme(M),
   pairrhyme(N,O),
   format("~a ~a ~a ~a~n",[M,N,O,F]),
   Y1 is Y-1,
   % If we "cut" here, we will always choose the same solution... 
   generatepoem(Y1).

更好的是建立一个行列表generatepoem并输出一次,而不是“在证明搜索期间”执行副作用。

请注意以下事项:

  1. 因为generatepoem/1如果参数为 0,我们会成功而没有进一步的副作用,否则我们会执行进一步的副作用。但是,“否则”的情况Y > 0. 如果我们不这样做,则证明搜索在基本情况 0 上成功,并且还有另一个generatepoem(0)执行副作用的解决方案,然后使用-1, -2, -3... 无限调用自身。
  2. 该解决方案不承诺在通过 generatepoem/1 的段落中做出的选择,因为我们不会在我发表评论的地方“剪切”。所以通过回溯,我们最终会生成所有可能的诗歌,但这并不是很有趣。最好随机选择一首诗...

改代码构造解,然后输出一次

先解决一连串format/2电话的丑陋:

generatepoem([],0).
generatepoem([[A,B,C,D],[G,H,I,E],[J,K,L],[M,N,O,F]|More],Y):- 
   Y > 0,
   norhyme(A),
   pairrhyme(B,C),
   triplerhyme(D,E,F),
   norhyme(G),
   pairrhyme(H,I),
   pairrhyme(J,K),
   norhyme(L),
   norhyme(M),
   pairrhyme(N,O),
   Y1 is Y-1,
   generatepoem(More,Y1).

dump([]) :- !.
dump([[A,B,C,D]|More]) :-
  !,
  format("~a ~a ~a ~a~n",[A,B,C,D]),
  dump(More).
dump([[A,B,C]|More]) :-
  format("~a ~a ~a~n",[A,B,C]),
  dump(More).

注意正文中的切口dump/2告诉 Prolog 没有替代解决方案(SWI-Prolog 本身看不到这一点)。

现在可以通过以下方式生成诗歌流:

?- generatepoem(L,2),dump(L).

更改代码以随机构造解决方案(虽然我们不能回溯)

这是通过利用 and 的力量来完成的bagof/3random_between/3后者明显是一个非逻辑谓词):

当一切已经说过并且做完了:

norhyme(anun).
norhyme(unuri).
norhyme(sicom).
norhyme(kana).

pairrhyme_one_way(kura,tama).
pairrhyme_one_way(bimo,co).
pairrhyme_one_way(sonen,ariten).
pairrhyme_one_way(te,shime).
pairrhyme_one_way(su,kuru).
pairrhyme_one_way(kuru,shanadu).
pairrhyme_one_way(su,xanadu).

pairrhyme(X,Y) :- pairrhyme_one_way(X,Y).
pairrhyme(X,Y) :- pairrhyme_one_way(Y,X).

triplerhyme(su,kuru,xanadu).

% we need a 1-arg equivalent to pairrhyme/2 

pairrhyme_tuple([X,Y]) :- pairrhyme_one_way(X,Y).
pairrhyme_tuple([X,Y]) :- pairrhyme_one_way(Y,X).

% non-backtrackably select a random element from a list

randomly_select(List,Element) :-
   length(List,Length),
   MaxIndex is Length-1,
   random_between(0,MaxIndex,Index), % fails if MaxIndex < 0, i.e. if List is empty
   nth0(Index,List,Element).

% non-backtrackably select a random solution of Goal
% this works because our Goals do not generate all that many solutions

random_solution(Goal,Element) :-
   bagof(X,call(Goal,X),Bag), % fails if there is no solution
   randomly_select(Bag,Element).

% an equivalent of nohryme/1 which non-backtrackably selects a random solution

norhyme_randomly(X)     :- random_solution(norhyme,X).

% an equivalent of pairrhyme/2 which non-backtrackably selects a random solution

pairrhyme_randomly(X,Y) :- random_solution(pairrhyme_tuple,[X,Y]).

% an equivalent of generatepoen/2 which non-backtrackably selects a random solution

generatepoem_randomly([],0).
generatepoem_randomly([[A,B,C,D],[G,H,I,E],[J,K,L],[M,N,O,F]|More],Y):- 
   Y > 0,
   norhyme_randomly(A),
   pairrhyme_randomly(B,C),
   triplerhyme(D,E,F),
   norhyme_randomly(G),
   pairrhyme_randomly(H,I),
   pairrhyme_randomly(J,K),
   norhyme_randomly(L),
   norhyme_randomly(M),
   pairrhyme_randomly(N,O),
   Y1 is Y-1,
   generatepoem_randomly(More,Y1).

dump([]) :- !.
dump([[A,B,C,D]|More]) :-
  !,
  format("~a ~a ~a ~a~n",[A,B,C,D]),
  dump(More).
dump([[A,B,C]|More]) :-
  format("~a ~a ~a~n",[A,B,C]),
  dump(More).

所以:

?- generatepoem_random(L,2),dump(L).
unuri shime te su
sicom sonen ariten kuru
ariten sonen unuri
anun kura tama xanadu
kana shime te su
unuri su xanadu kuru
te shime sicom
kana su xanadu xanadu

推荐阅读