Prolog 查找给定员工姓名是否属于两个不同的员工Id';s

Prolog 查找给定员工姓名是否属于两个不同的员工Id';s,prolog,Prolog,我有员工(emp\u id,emp\u name)形式的序言事实,如图所示: employee(101,'Jack'). employee(102,'Tom'). employee(103,'Adam'). employee(104,'John'). employee(105,'Jack'). employee(106,'Adam'). employee(107,'Bob'). employee(108,'Pat'). employee(109,'Adam'). employee(110,'Jo

我有
员工(emp\u id,emp\u name)
形式的序言事实,如图所示:

employee(101,'Jack').
employee(102,'Tom').
employee(103,'Adam').
employee(104,'John').
employee(105,'Jack').
employee(106,'Adam').
employee(107,'Bob').
employee(108,'Pat').
employee(109,'Adam').
employee(110,'Joe').
现在,我想写一个子句
“给定的员工姓名是否属于两个不同的员工id?”
它应该返回true/false

我知道这似乎是非常基本的,但作为一个初学者,我对它印象深刻。

您可以使用它来获取任何员工拥有的员工ID列表,并且只有在该列表中至少有2个ID时才能成功:

multiple_employee(Name):-
  setof(Id, employee(Id, Name), [_,_|_]).  % there are at least 2 ids
运行示例:

?- multiple_employee('Jack').
true.

?- multiple_employee('Tom').
false.

?- multiple_employee(X).
X = 'Adam' ;
X = 'Jack' ;
false.
您可以使用获取任何员工拥有的员工ID列表,并且只有当该列表中至少有2个ID时,才能成功:

multiple_employee(Name):-
  setof(Id, employee(Id, Name), [_,_|_]).  % there are at least 2 ids
运行示例:

?- multiple_employee('Jack').
true.

?- multiple_employee('Tom').
false.

?- multiple_employee(X).
X = 'Adam' ;
X = 'Jack' ;
false.
这应该做到:

different(X, Y) :-
   employee(IX, X), 
   employee(IY, Y), 
   IX \== IY.

employee(101,'Jack1').
employee(102,'Tom').
employee(103,'Adam1').
employee(104,'John').
employee(105,'Jack2').
employee(106,'Adam2').
employee(107,'Bob').
employee(108,'Pat').
employee(109,'Adam3').
employee(110,'Joe').

?- different('Joe', 'Pat').
true.
?- different('Jack1', 'Jack1').
false.
名称必须是唯一的,否则就无法区分say Jack(id 101)和Jack(id 105)。否则,您的模型会出现语法歧义,并且不会产生任何好处。

这应该可以做到:

different(X, Y) :-
   employee(IX, X), 
   employee(IY, Y), 
   IX \== IY.

employee(101,'Jack1').
employee(102,'Tom').
employee(103,'Adam1').
employee(104,'John').
employee(105,'Jack2').
employee(106,'Adam2').
employee(107,'Bob').
employee(108,'Pat').
employee(109,'Adam3').
employee(110,'Joe').

?- different('Joe', 'Pat').
true.
?- different('Jack1', 'Jack1').
false.

名称必须是唯一的,否则就无法区分say Jack(id 101)和Jack(id 105)。否则,您的模型会出现语法歧义,并且不会产生任何好处。

对peter.cyc的答案进行了修改:

同名员工(姓名,Id1,Id2):-
dif(Id1,Id2),%表示Id1和Id2总是“不同”(不能统一,根据“\=”)
员工(Id1,名称),%获取员工记录,从而修复Id1和名称
员工(Id2,姓名)。%获取另一个具有以前姓名的员工记录,修复Id2
%dif/2约束确保Id1\=Id2
雇员(101,“杰克”)。
雇员(102,“汤姆”)。
雇员(103,“亚当”)。
雇员(104,“约翰”)。
雇员(105,“杰克”)。
雇员(106,“亚当”)。
雇员(107,“鲍勃”)。
雇员(108,“帕特”)。
雇员(109,“亚当”)。
雇员(110,“乔”)。
然后:

-
具有相同名称(N、Id1、Id2)的员工。
N=‘杰克’,
Id1=101,
Id2=105;
N=‘亚当’,
Id1=103,
Id2=106;
N=‘亚当’,
Id1=103,
Id2=109;
N=‘杰克’,
Id1=105,
Id2=101;
N=‘亚当’,
Id1=106,
Id2=103;
N=‘亚当’,
Id1=106,
Id2=109;
N=‘亚当’,
Id1=109,
Id2=103;
N=‘亚当’,
Id1=109,
Id2=106;
错。
一种变体,将它们全部收集到一个列表中

我还不能用setof-in-setof-with-caret语法实现这一点。有时候序言就是这样。那么最好使用单独的谓词。此版本首先将所有名称收集在一个单独的名称列表中

同名员工(整体):-
集合(姓名,SomeId^员工(SomeId,姓名),姓名),
一套(
名字换名字,
(成员(姓名),
员工姓名相同(姓名,ForName)),
总体而言)。
具有相同姓名的员工(姓名,ForNameSorted):-
bagof(IdX,employee(IdX,Name),ForName),%保留副本(不应该有任何副本)
来自gusbro解决方案的ForName=[u,124;],%必须至少有两个该名称的ID
msort(ForName,ForNameSorted)。%分类?为什么不呢?使用msort/2保留重复项
?-员工姓名相同(O)。
O=['Adam'-[103106109],'Jack'-[101105]]。
这当然是SQL语句

SELECT E1.Name FROM Employee E1 WHERE EXISTS
   SELECT * FROM Employee E2 WHERE E2.Name = E1.Name AND E2.Id <> E1.Id
从存在的员工E1中选择E1.Name
从Employee E2中选择*,其中E2.Name=E1.Name和E2.Id E1.Id

对peter.cyc答案的修改:

同名员工(姓名,Id1,Id2):-
dif(Id1,Id2),%表示Id1和Id2总是“不同”(不能统一,根据“\=”)
员工(Id1,名称),%获取员工记录,从而修复Id1和名称
员工(Id2,姓名)。%获取另一个具有以前姓名的员工记录,修复Id2
%dif/2约束确保Id1\=Id2
雇员(101,“杰克”)。
雇员(102,“汤姆”)。
雇员(103,“亚当”)。
雇员(104,“约翰”)。
雇员(105,“杰克”)。
雇员(106,“亚当”)。
雇员(107,“鲍勃”)。
雇员(108,“帕特”)。
雇员(109,“亚当”)。
雇员(110,“乔”)。
然后:

-
具有相同名称(N、Id1、Id2)的员工。
N=‘杰克’,
Id1=101,
Id2=105;
N=‘亚当’,
Id1=103,
Id2=106;
N=‘亚当’,
Id1=103,
Id2=109;
N=‘杰克’,
Id1=105,
Id2=101;
N=‘亚当’,
Id1=106,
Id2=103;
N=‘亚当’,
Id1=106,
Id2=109;
N=‘亚当’,
Id1=109,
Id2=103;
N=‘亚当’,
Id1=109,
Id2=106;
错。
一种变体,将它们全部收集到一个列表中

我还不能用setof-in-setof-with-caret语法实现这一点。有时候序言就是这样。那么最好使用单独的谓词。此版本首先将所有名称收集在一个单独的名称列表中

同名员工(整体):-
集合(姓名,SomeId^员工(SomeId,姓名),姓名),
一套(
名字换名字,
(成员(姓名),
员工姓名相同(姓名,ForName)),
总体而言)。
具有相同姓名的员工(姓名,ForNameSorted):-
bagof(IdX,employee(IdX,Name),ForName),%保留副本(不应该有任何副本)
来自gusbro解决方案的ForName=[u,124;],%必须至少有两个该名称的ID
msort(ForName,ForNameSorted)。%分类?为什么不呢?使用msort/2保留重复项
?-员工姓名相同(O)。
O=['Adam'-[103106109],'Jack'-[101105]]。
这当然是SQL语句

SELECT E1.Name FROM Employee E1 WHERE EXISTS
   SELECT * FROM Employee E2 WHERE E2.Name = E1.Name AND E2.Id <> E1.Id
从存在的员工E1中选择E1.Name
从Employee E2中选择*,其中E2.Name=E1.Name和E2.Id E1.Id

我的解决方案非常基本:-

检查谓词检查您正在检查的名称。findall查找所有具有该名称的记录。如果记录为2或大于2,则返回true,否则返回false

check(A):-
    findall(A,employee(_,A),LA),
    length(LA,Len),
    Len>=2.

?-check('Jack').
true
?-check('Adam').
true
?-check('Tom').
false
如果您只想检查名称是否仅为其两次,请将Len>=2更改为Len=2。

DuDa建议后的更新:check会给我列表中出现两次的所有名字的列表注意:我添加了Joe的另一个记录,因此程序应该返回Jack和Jo