使用prolog来解决找到在一个人下工作的所有员工,包括间接地。

时间:2015-12-02 11:05:19

标签: prolog

如果我的员工条目显示员工的姓名以及直接在该人员下工作的所有人员,例如:

employee(joe, []).  
employee(billy, []).  
employee(mike, [joe, billy]).  
employee(megan, [mike]).  
employee(tom, [joe, megan]).  
employee(bob, [billy]).  
employee(kate, [tom, bob, joe]).  

如何获得一份列表,其中包含直接或间接在某个员工下工作的所有人员?

如果我输入:

bossof(megan, Output). 

让所有人都在megan下工作,它给了我一个输出:

Output = [mike, joe, billy]. 

到目前为止,我一直试图以这种方式递归地进行:

bossof(X, A) :- getloweremployees(employee(X,Y), A).

getloweremployees([],_).
getloweremployees([H|T], A) :- A = append([H], getloweremployees(employee(H,Z),B), getloweremployees(T, C)).

但它只是给了我一个虚假的输出。困扰我的主要部分是弄清楚如何分解列表以尝试每个数据。

任何提示都将不胜感激。

2 个答案:

答案 0 :(得分:2)

如果您要求您的事实与原始帖子中所述相同,那么您可以定义以下规则来确定特定“老板”的员工:

% Boss is the boss of Employee if Employee' is a member of Boss' employees
%
boss_of(Boss, Employee) :-
    employee(Boss, Employees),
    member(Employee, Employees).

% Boss is the boss of Employee if E is one of Boss' employees, and E is a boss of Employee
%
boss_of(Boss, Employee) :-
    employee(Boss, Employees),
    member(E, Employees),
    boss_of(E, Employee).

如果BossEmployee的老板,则会成功:

| ?- boss_of(megan, Output).

Output = mike ? ;

Output = joe ? ;

Output = billy

yes
| ?-

然后使用findall/3收集所有回复:

boss_of_all(Boss, Employees) :-
    findall(E, boss_of(Boss, E), Employees).

作为测试查询:

| ?-  boss_of_all(megan, Employees).

Employees = [mike,joe,billy]

yes
| ?-

就个人而言,我会将您的事实命名为employees/2而不是employee/2,因为事实会产生给定老板的所有员工,而不仅仅是一个。在Prolog中建立逻辑和一致的命名约定(如在任何语言中)将有助于使程序更易于理解和设计。

<小时/> 然而,作为一种替代方法,我认为将员工事实表示为个人老板/员工关系会更简单,更灵活,更规范。

employee(mike, billy). 
employee(mike, joe). 
employee(megan, mike).  
employee(tom, joe).
employee(tom, megan).
employee(bob, billy).  
employee(kate, tom).  
employee(kate, bob).  
employee(kate, joe).

根据这些事实,您将得到一个查询,例如:

| ?- employee(mike, X).

X = billy ? ;

X = joe

yes

因此,Prolog将回溯以获得每个解决方案(员工为mike)。带有列表参数的事实可以通过简单的谓词从这些事件中派生出来:

employees(X, Employees) :- findall(E, employee(X, E), Employees).

这样,以下查询将以您当前事实数据库的方式执行:

| ?- employees(tom, Employees).

Employees = [joe,megan]

yes
| ?-

鉴于这一切,如果满足以下任一条件,则可以说 BE 的老板:

  

BE

员工      

XB员工,而X boss_of E

这些可以表示为:

boss_of(B, E) :- employee(B, E).
boss_of(B, E) :- employee(B, X), boss_of(X, E).

boss_of/2的行为如上面的第一个解决方案所示。如果boss_of(X, Y)X的老大,则谓词Y为真。如果您确实需要在列表中收集这些结果,则应完全按照上面第一个解决方案中的说明定义boss_of_all/2

答案 1 :(得分:1)

递归方法可能是:

boss_employees(Boss, Employees) :-
    employee(Boss, Direct),
    findall(L, ( member(D, Direct), boss_employees(D, L) ), Lt),
    flatten([Direct, Lt], Sub),
    sort(Sub, Employees).

而不是flatten / 2,我们可以使用append / 2,因为嵌套总是1级

    ...
    append([Direct|Lt], Sub),
    ...