Prolog 更改事实顺序会产生不同的结果
Prolog change order of facts produces different outcomes
序言新手。我有一个无法解释的小故障,但如果我添加其他字典 (X) 事实,该程序似乎可以正常工作。该程序采用一个字符串列表,其中的字母已被编码,并生成一个解码列表。每个字母代表单词列表中的一个不同字母。所以 go([abccd,edfgh,ade,ifb,kdl],X) returns X = ['HELLO', 'WORLD', 'HOW', 'ARE', 'YOU']。问题是如果字典('HOW')事实出现在字典('YOU')事实之前,那么程序 returns 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 很酷。感谢您的帮助。
几点:
- 我认为你有';'优先级错误,需要另一组括号。
- 双 HOW 实际上是一个有效的答案,因为你没有检查,例如'a' 和 'k' 都映射到 H(碰巧,中间的 'O' 适合两个 3 字母模式)。
- 可能有更 'Prolog' 的方法来解决您的问题,通过使用 vars 的自然统一,即
将 [abccd,edfgh,ade,ifb,kdl] 表示为类似的变量列表:
[[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).
请注意,这仍然与您的代码具有相同的 'bug' - 没有检查所有变量是否匹配不同的字母 - 您必须为此编写代码...
我的解决方案让我明白了问题是从哪里出来的
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.
序言新手。我有一个无法解释的小故障,但如果我添加其他字典 (X) 事实,该程序似乎可以正常工作。该程序采用一个字符串列表,其中的字母已被编码,并生成一个解码列表。每个字母代表单词列表中的一个不同字母。所以 go([abccd,edfgh,ade,ifb,kdl],X) returns X = ['HELLO', 'WORLD', 'HOW', 'ARE', 'YOU']。问题是如果字典('HOW')事实出现在字典('YOU')事实之前,那么程序 returns 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 很酷。感谢您的帮助。
几点:
- 我认为你有';'优先级错误,需要另一组括号。
- 双 HOW 实际上是一个有效的答案,因为你没有检查,例如'a' 和 'k' 都映射到 H(碰巧,中间的 'O' 适合两个 3 字母模式)。
- 可能有更 'Prolog' 的方法来解决您的问题,通过使用 vars 的自然统一,即
将 [abccd,edfgh,ade,ifb,kdl] 表示为类似的变量列表:
[[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).
请注意,这仍然与您的代码具有相同的 'bug' - 没有检查所有变量是否匹配不同的字母 - 您必须为此编写代码...
我的解决方案让我明白了问题是从哪里出来的
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.