微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Prolog:字符列表 <=> 字符列表列表

如何解决Prolog:字符列表 <=> 字符列表列表

我正在实现一个 words/2 谓词,其中可以将字符列表作为列表中的单词呈现到字符列表中。我使用数学符号 <=> 表示它们在任何模式下工作。有更好的表达方式请指教。

例子:

?- words([p,r,o,l,g,' ',i,s,d],Y).
Y = [[p,g],[i,s],[g,d]]

?- words(X,[[p,d]]).
X = [p,d]

我所做的是尝试使用 append/3 如下,尝试将空字符串放在中间,并将它们连接在一起。并使用 List 递归 NewCharList,但因“超出本地堆栈”而失败。

% base case,empty list
words([],[]).
% X is a list of characters
% Y is a list with characters list as a word
words(CharList,[WordList|List]):-
    append(WordList,[' '],NewWord),append(NewWord,CharList,NewCharList),words(NewCharList,List).

我该如何改进代码?谢谢。

编辑 1 来自@rajashekar 的百万感谢。现在我明白代码

% base case
split(_,[],[[]]).

% when the the element list of Ys is empty
% add a C to the Xs,in this case,C is a empty string ' '
split(C,[C|Xs],[[]|Ys]) :-
    split(C,Xs,Ys).

% put the X character from [X|Y] list to Xs
% and goes on next word list
split(C,[X|Xs],[[X|Y]|Ys]) :-
    split(C,[Y|Ys]).

但在我的 SWI 序言中,这似乎很奇怪:

?-split(' ',X,s|...]

这是跟踪记录:

[trace]  ?- split(X,d]]).
   Call: (10) split(_5702,d]]) ? creep
   Call: (11) split(_6210,[[r,d]]) ? creep
   Call: (12) split(_6266,[[o,d]]) ? creep
   Call: (13) split(_6322,[[l,d]]) ? creep
   Call: (14) split(_6378,d]]) ? creep
   Call: (15) split(_6434,[[g],d]]) ? creep
   Call: (16) split(_6490,[[],d]]) ? creep
   Call: (17) split(_6546,[[i,d]]) ? creep
   Call: (18) split(_6596,[[s],d]]) ? creep
   Call: (19) split(_6652,d]]) ? creep
   Call: (20) split(_6708,[[g,d]]) ? creep
   Call: (21) split(_6758,d]]) ? creep
   Call: (22) split(_6814,d]]) ? creep
   Call: (23) split(_6870,[[d]]) ? creep
   Call: (24) split(_6926,[[]]) ? creep
   Exit: (24) split([],[[]]) ? creep
   Exit: (23) split([d],[[d]]) ? creep
   Exit: (22) split([o,d]]) ? creep
   Exit: (21) split([o,d]]) ? creep
   Exit: (20) split([g,d]]) ? creep
   Exit: (19) split([' ',d]]) ? creep
   Exit: (18) split([s,d]]) ? creep
   Exit: (17) split([i,d]]) ? creep
   Exit: (16) split([' ',d]]) ? creep
   Exit: (15) split([g,o|...],d]]) ? creep
   Exit: (14) split([o,d]]) ? creep
   Exit: (13) split([l,g|...],d]]) ? creep
   Exit: (12) split([o,' '|...],d]]) ? creep
   Exit: (11) split([r,s|...],d]]) ? creep
   Exit: (10) split([p,i|...],d]]) ? creep
X = [p,s|...] .

EDIT2 我发现使用 ! (cut) 可以减少回溯。

% base case
split(_,Ys),!.

% put the X character from [X|Y] list to Xs
% and goes on next word list
split(C,[Y|Ys]),!.

解决方法

代码完全符合您的要求。 这里:

to_round

X 正是预期的输出。

如果您想查看所有 X,请执行以下操作:

?-split(' ',X,[[p,r,o,l,g],[i,s],[g,d]]).
X = [p,g,' ',i,s|...]

SWI prolog 输出中的长列表被缩短。

,
split(_,[],[[]]).
split(C,[C|Xs],[[]|Ys]) :-
    split(C,Xs,Ys).
split(C,[X|Xs],[[X|Y]|Ys]) :-
    split(C,[Y|Ys]).
| ?- split(' ',[p,s,d],X).

X = [[p,d]] ? 

yes
| ?- split(' ',d]]).

X = [p,d] ? 

yes
  • 你可以使用模式声明来说明谓词在两种模式下都有效。例如,您可以说 words/2 谓词需要在 words(+Chars,-Words)words(-Chars,+Words) 模式下(或在 words(+,-)words(-,+) 模式下)工作。 See 了解模式详情。这些主要用于 prolog 中的文档目的(查看 mercury 它们真正起作用的地方)。
  • 使用 Definite Clause Grammers DCG 将使此类问题变得更容易。
  • 当您感觉递归失控时,请尝试使用 trace。如果您使用它,大多数时候您都可以发现问题。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。