给定知识库的 Prolog 谜题 - 不工作
Posted
技术标签:
【中文标题】给定知识库的 Prolog 谜题 - 不工作【英文标题】:Prolog puzzle with given Knowledge Base - Not Working 【发布时间】:2017-10-29 14:03:12 【问题描述】:我知道题目的标题在这里:A prolog program that reflects people sitting at a round table
但我需要一个不同的解决方案,更简单。
所以我遇到了一个问题,即 4 个人围坐在一张方桌旁。
我们知道他们的名字。 有人是骨科医生,有人是牙医,有人是外科医生,有人是儿科医生。
我们有一个您将在代码中看到的知识库。
我们必须找到儿科医生的名字。
我的程序找到了它,但没有打印出代表桌子上座位的列表的所有四种可能组合。
table(List):-
length(List,4),
member(convive(argiro,_,female),List),
member(convive(georgia,_,female),List),
member(convive(basilis,_,male),List),
member(convive(dimitris,_,male),List),
left(convive(_,dentist,_),convive(argiro,_,female),List),
oppo(convive(_,surgeon,_),convive(basilis,_,male),List),
next(convive(georgia,_,female),convive(dimitris,_,male),List),
left(convive(_,_,female),convive(_,orthopedist,_),List),
member(convive(_,pediatrecian,_),List).
left(X,Y,ConLs):-append(_,[X,Y|_],ConLs).
left(X,Y,ConLs):-prefix(X,ConLs),last(ConLs,Y).
next(X,Y,ConLs):-left(X,Y,ConLs).
next(X,Y,ConLs):-append(_,[Y,X|_],ConLs).
next(X,Y,ConLs):-prefix(Y,ConLs),last(ConLs,X).
oppo(X,Y,ConLs):-next(X,Z,ConLs),next(Z,Y,ConLs),X\==Y.
在我得到的终端上:
?- table(List),member(convive(Name,pediatrecian,_),List).
List = [convive(basilis, 牙医, 男性), convive(argiro, 儿科, 女性), convive(格鲁吉亚, 外科医生, 女性), convive(dimitris, 骨科医生, 男性)], 名称 = argiro ;
List = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)], 名称 = argiro ;
假的。
如您所见,我得到了名字,但只有 2 个可能的列表表示每个人的座位。还应该有:
List = [convive(dimitris, 骨科医生, 男性), convive(basilis, 牙医, 男性), convive(argiro, 儿科, 女性), convive(georgia, 外科医生, 女性)]
List = [convive(argiro, pediatrecian, 女性), convive(georgia, 外科医生, 女性), convive(dimitris, 骨科医生, 男性), convive(basilis, 牙医, 男性)]
我已经使用了这些线条
left(X,Y,ConLs):-prefix(X,ConLs),last(ConLs,Y).
next(X,Y,ConLs):-prefix(Y,ConLs),last(ConLs,X).
但是,它们什么也没做,如果我删除它们,我会得到相同的结果。
更新
table(List):-
length(List,4),
member(convive(argiro,_,female),List),
member(convive(georgia,_,female),List),
member(convive(basilis,_,male),List),
member(convive(dimitris,_,male),List),
left(convive(_,dentist,_),convive(argiro,_,female),List),
oppo(convive(_,surgeon,_),convive(basilis,_,male),List),
next(convive(georgia,_,female),convive(dimitris,_,male),List),
left(convive(_,_,female),convive(_,orthopedist,_),List),
member(convive(_,pediatrecian,_),List).
left(X,Y,ConLs):-append(_,[X,Y|_],ConLs).
left(X,Y,ConLs):-prefix(X,ConLs),last(ConLs,Y).
next(X,Y,ConLs):-left(X,Y,ConLs);left(Y,X,ConLs).
%next(X,Y,ConLs):-append(_,[Y,X|_],ConLs).
next(X,Y,ConLs):-prefix(Y,ConLs),last(ConLs,X).
%oppo(X,Y,ConLs):-next(X,Z,ConLs),next(Z,Y,ConLs),X\==Y.
oppo(X,Y,[X,_,Y,_]).
oppo(X,Y,[Y,_,X,_]).
oppo(X,Y,[_,X,_,Y]).
oppo(X,Y,[_,Y,_,X]).
所以,oppo/3 似乎在给定列表上运行良好
?- table(List), oppo(convive(argiro,pediatrecian,female),Name,List)。
列表 = [convive(basilis, 牙医, 男性), convive(argiro, 儿科, 女性), convive(georgia, 外科医生, 女性), convive(dimitris, 骨科医生, 男性)],
姓名 = convive(dimitris, 骨科医生, 男性) ;
List = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)],
姓名 = convive(dimitris, 骨科医生, 男性) ;
假的。
left/3 似乎在做与我首先要解决的相同的事情,它适用于 argiro 为 2 且 georgia 为 3 的列表,这是一个简单的情况,但在您可以在 oppo/3 结果中看到上面的第二个列表,其中 argiro 是第 4 号,georgia 是第 1 号,它应该看到 georgia 再次在 argiro 的左侧,但不是。
?- table(List), left(convive(argiro,pediatrecian,female),Name,List)。
列表 = [convive(basilis, 牙医, 男性), convive(argiro, 儿科, 女性), convive(georgia, 外科医生, 女性), convive(dimitris, 骨科医生, 男性)],
姓名 = convive(格鲁吉亚,外科医生,女性);
假的。
现在 next/3 返回一些非常令人不安的结果。我不知道该怎么做,我是Prolog的新手。有些还可以,但有些似乎将整个数组作为结果,有些说 List = Name。
前三个结果没问题,第四个和left/3一样,看不到列表中的第一个在最后一个的旁边,所以它返回一个空数组。
这里发生了什么?
?- table(List), next(convive(argiro,pediatrecian,female),Name,List)。
列表 = [convive(basilis, 牙医, 男性), convive(argiro, 儿科, 女性), convive(georgia, 外科医生, 女性), convive(dimitris, 骨科医生, 男性)],
姓名 = convive(格鲁吉亚,外科医生,女性);
列表 = [convive(basilis, 牙医, 男性), convive(argiro, 儿科, 女性), convive(georgia, 外科医生, 女性), convive(dimitris, 骨科医生, 男性)],
姓名 = convive(basilis, 牙医, 男性) ;
List = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)],
姓名 = convive(basilis, 牙医, 男性) ;
List = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)],
名称 = [] ;
List = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)],
姓名 = [convive(格鲁吉亚,外科医生,女性)] ;
List = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)],
姓名 = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性)] ;
List = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)],
姓名 = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性)] ;
列表 = 名称,
姓名 = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)] ;
List = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)],
名称 = [] ;
List = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)],
姓名 = [convive(格鲁吉亚,外科医生,女性)] ;
List = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)],
姓名 = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性)] ;
List = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)],
姓名 = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性)] ;
列表 = 名称,
姓名 = [convive(格鲁吉亚,外科医生,女性),convive(dimitris,骨科医生,男性),convive(basilis,牙医,男性),convive(argiro,儿科医师,女性)] ;
假的。
更新
所以我了解到 prefix/2 适用于字符串,例如,
prefix(x,[x,y,z]).
返回错误。
这就是它不起作用的原因,这解释了 next/3 中的结果,但我的问题仍然没有解决。
还有其他方法可以让 left 和 next 与列表的第一部分和最后一部分一起工作吗?
【问题讨论】:
我知道了名字,但列表应该是四个。我不确定那是什么意思。你能更准确地描述你认为答案应该是什么吗?四什么?table(List)
产生一个包含 4 个元素的列表。他们是正确的吗?然后你的 member
调用只选择其中一个,因为该调用的第一个参数的条件。
我编辑了它。我想我说得更清楚了,如果您仍有疑问,请提出。
虽然问题与链接的问题相似,但我认为您的问题的规则与解决方案相关,并且与链接中的规则不同。例如,您的代码假定桌子周围有 4 人(不是 5 人),并且正好有 2 名男性和 2 名女性。您没有将其作为一项规则声明,因此我不清楚您执行此类规则的代码是否正确。您可能希望对辅助谓词left/3
、next/3
和oppo/3
运行单独的测试,以确保它们正常工作。您可以在 Prolog 提示符下直接调用 then。
prefix/3
和 last/3
定义在哪里?
好的,谢谢。我不知道所有的 SWI 内置插件。
【参考方案1】:
我敢打赌,罪魁祸首是oppo
中的\==
,因为这些谓词在这里以生成方式使用。试着摆脱它。只需手动编码四种可能性就足够了 - 毕竟,您的列表长度固定且非常短:
oppo(X,Y,[X,_,Y,_]).
.....
如果将next/3
编码为对left/3
的两个调用的析取,那么next/3
会更容易/更清晰。
对于left/3
本身,您也可以通过您的ConLs
形成一个圆圈
circle_up(Ls,Circle):- head(A,Ls), append(Ls,[A],Circle).
并在对append
的一次简单调用中使用Circle
来完成left/3
的定义。这假设定义
head(A,L):- L=[A|_].
【讨论】:
好的,所以我做了更改(我更新了帖子),除了最后一个,因为我不太明白。如果您能更详细地解释它,那就太好了。circle_up([A,B,C,D],Circle)
=> Circle=......
。然后,append(_, .... ,Circle)
解决了它。试试吧。 (假设定义prefix(A,L):- L=[A|_].
)。
什么时候next(X,Y,L)
?是left(X,Y,L)
或left(..., ..., L)
。正确的? ;)
是的,这确实成功了。你对 oppo/3 的看法也是对的。
好消息! ___以上是关于给定知识库的 Prolog 谜题 - 不工作的主要内容,如果未能解决你的问题,请参考以下文章