【问题标题】:Prolog change order of facts produces different outcomesProlog改变事实的顺序产生不同的结果
【发布时间】:2015-06-21 06:06:58
【问题描述】:

Prolog 的新手。我有一个无法解释的小故障,但如果我添加其他字典(X)事实,该程序似乎可以工作。该程序采用一个字符串列表,其中字母已被编码并生成一个解码列表。每个字母代表单词列表中的不同字母。所以 go([abccd,edfgh,ade,ifb,kdl],X) 返回 X = ['HELLO', 'WORLD', 'HOW', 'ARE', 'YOU']。问题是如果 dictionary('HOW') 事实出现在 dictionary('YOU') 事实之前,那么程序返回 X = ['HELLO', 'WORLD', 'HOW', 'ARE', 'HOW'] .这是故障代码:

/*word bank*/
dictionary('HELLO').
dictionary('WORLD').
dictionary('HOW').
dictionary('ARE').
dictionary('YOU').

/*This spits out a single list where
the lengths of words in the dictionary
are matched to each word in the encoded 
message, so [abccd,edfgh,ade,ifb,kdl]
matches [HELLO,WORLD,HOW,ARE,HOW] or
any combination*/ 
sameLength([X|XTail],[Y|YTail]) :-
   dictionary(Y),
   name(X,L1),name(Y,L2),
   length(L1,Z),length(L2,Z),
   sameLength(XTail,YTail).
sameLength([],[]).

/*Turns a list of lists into
a single list*/
oneWord([X|XTail],Y) :-
   name(X,L),
   append(L,Z,Y),
   oneWord(XTail,Z).
oneWord([],[]).

/*This replaces the letters that are in
the dictionary, with the letters in the
message.  If at any point a letter has
been replaced because it is UPPERCASE,
and that letter is being replaced by
something else then fail, other wise,
the letter has to be lowercase*/
replaceLetters(List,[X|XTail],[Y|YTail],Result) :-
   (X<91,X=Y);(X>96),
   replaceP(X,Y,List,Result1),
   replaceLetters(Result1,XTail,YTail,Result).
replaceLetters(Result,[],[],Result).

/*the call to action*/
go(X,Y) :-
   sameLength(X,Y),
   oneWord(X,A),
   oneWord(Y,B),
   replaceLetters(A,A,B,C),
   B=C,
   !.

/*replace thanks to @repeat*/
replaceP(_, _, [], []).
replaceP(O, R, [O|T], [R|T2]) :- replaceP(O, R, T, T2).
replaceP(O, R, [H|T], [H|T2]) :- dif(H,O), replaceP(O, R, T, T2).

我想补充一点,Prolog 很酷。感谢您的帮助。

【问题讨论】:

  • +1 用于使用 dif/2!但是 name/2 已被弃用和过时了 3 多年 - 只有当您穿着 1970 年代的 2 英寸高原鞋时,您才能使用它。

标签: prolog


【解决方案1】:

我的解决方案让我明白问题是从哪里出来的

go(X,Y) :-
    go(X,Y,[]).

go([],[],_Dict).
go([W|Ws],[T|Ts],Dict) :-
    assoc_codes(W,T,Dict,DictUpd),
    go(Ws,Ts,DictUpd).

assoc_codes(W,T,Dict,DictUpd) :-
    atom_codes(W, Cs),
    dictionary(T),
    atom_codes(T, Tcs),
    upd_dict(Cs, Tcs, Dict, DictUpd).

upd_dict([], [], DictUpd, DictUpd). % done, all went well
upd_dict([C|Cs], [D|Ds], Dict, DictUpd) :-
        memberchk(C-T, Dict)    % if C already 'assigned', must match D
    ->  T = D,
        upd_dict(Cs, Ds, Dict, DictUpd)
    ;   \+ ( memberchk(X-D, Dict), X \= C ),
        upd_dict(Cs, Ds, [C-D|Dict], DictUpd).

注意else分支:当C还没有被赋值时,D也必须如此。如果我们把它注释掉(即

...
;   % \+ ( memberchk(X-D, Dict), X \= C ),
...

) 我们有您报告的问题

?- go([abccd,edfgh,ade,ifb,kdl],X).
X = ['HELLO', 'WORLD', 'HOW', 'ARE', 'HOW'] ;
X = ['HELLO', 'WORLD', 'HOW', 'ARE', 'YOU'] ;
false.

这是因为必须将“L”分配给“c”和“g”。 取消注释测试后,我们有

?- go([abccd,edfgh,ade,ifb,kdl],X).
false.

?- go([abccd,edfch,ade,ifb,kdl],X).
X = ['HELLO', 'WORLD', 'HOW', 'ARE', 'YOU'] ;
false.

【讨论】:

  • 感谢您花时间解决这个问题。我不明白语法 memberchk(C-T, Dict)。这是我不认识的 C-T 部分。
  • 只是一对字符代码,存储在我能想到的最简单的关联数据结构中:一对列表
  • 好的。我追踪了这一点,我看到了你在做什么。非常感谢!
【解决方案2】:

几点:

  1. 我认为你有';'优先级错误,需要另一组括号。
  2. 双重 HOW 实际上是一个有效的答案,因为您没有检查例如'a' 和 'k' 都映射到 H(偶然地,中​​间的 'O' 适合两个 3 字母模式)。
  3. 通过使用 vars 的自然统一,可能有一种更“Prolog”的方式来解决您的问题,即

将 [abccd,edfgh,ade,ifb,kdl] 表示为类似的 var 列表:

[[A,B,C,C,D],[E,D,F,G,H],[A,D,E],[I,F,B][K,D,L]]

并将您的字典存储为字母列表 例如

dictionary(['H','E','L','L','O']).
dictionary('['W','O','R','L','D']).

然后只需使用 Prolog 回溯匹配所有单词:

solve([],[]).
solve([Word|Ps],[Word|Words]) :- dictionary(Word), solve(Ps,Words).

并用类似的东西打电话

:- solve([[A,B,C,C,D],[E,D,F,G,H],[A,D,E],[I,F,B],[K,D,L]], Answer).

请注意,您的代码仍然存在相同的“错误” - 没有检查所有变量是否匹配不同的字母 - 您必须为此编写代码...

【讨论】:

  • 您好,谢谢! Transform 听起来像是一个很棒的解决方案,也是我最初在脑海中想象的解决方案的方式,但不知道如何去做。问题正是如何将一个潜在的无限列表表示为变量,所以我会试试这个。太棒了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-07-16
  • 2018-05-23
  • 2017-09-11
  • 2020-03-14
  • 1970-01-01
  • 1970-01-01
  • 2011-04-04
相关资源
最近更新 更多