سؤال

لديّ عدد كبير من الحقائق في برنامجي ، وسرد المطورين والمصممين في شركة ، وكذلك المشاريع السابقة ، مثل ذلك ..

% project(Project Name,Year)
project(efnet, 2007).
% designer(Project Name, Name, Role)
designer(efnet, jane_cole, lead).
% developer(Project Name, Name, Role)
developer(efnet, alex_tobbs, architect).

لقد قمت أيضًا ببناء تعريف يعرض قائمة بالمصممين أو المطورين الذين يعملون في مشروع

% employees(Single Project, List of Employees
employees(Project, E)

ما أريده هو إنشاء تعريف جديد يأخذ قائمة بالمصممين أو المطورين ويعرض قائمة بجميع عناوين المشروع التي عملوا عليها (P) ؛ مثل ذلك..

% projects_of_all(List of Staff, List of Projects)
projects_of_all(S,P):- ...

يمكنني القيام بذلك بسهولة مع Findall (أو Bagof) إذا كان عليّ العثور على أفلام شخص واحد ، لكنني لست متأكدًا من كيفية القيام بذلك مع قائمة الموظفين. هل يمكن لأحد أن يعطيني يد العون مع هذا؟

هل كانت مفيدة؟

المحلول

النظر في ما يلي التي لا تعتمد على جميع الحلقات المدمجة مثل findall, setof أو bagof:

% employees(Single Project, List of Employees
employees(Project, Employees) :-
    employees(Project, [], Employees).

employees(Project, Acc, Employees) :-
    (   designer(Project, Employee, _)
    ;   developer(Project, Employee, _)
    ),
    \+ member(Employee, Acc), !,
    employees(Project, [Employee|Acc], Employees).
employees(_Project, Employees, Employees).

يتراكم هذا الإصدار قائمة فريدة من الموظفين العاملين في المشروع. وبالمثل ، فإن تنفيذ مسندك projects_of_all/2 يمكن أن يكون على هذا النحو:

% projects_of_all(List of Staff, List of Projects)
projects_of_all(Employees, Projects):- 
    projects_of_all(Employees, [], Projects).

projects_of_all(Employees, Acc, Projects):-
    \+ var(Employees),
    member(Employee, Employees),
    (   designer(Project, Employee, _)
    ;   developer(Project, Employee, _)
    ),
    \+ member(Project, Acc), !,
    projects_of_all(Employees, [Project|Acc], Projects).
projects_of_all(_Employees, Projects, Projects). 

لاحظ الفرعية الحارس \+ var(Employees), ، لأننا لا نريد كلا الحجتين إلى الدعوة إلى member(Employee, Employees) لكي تكون غير محدود تمامًا ، مما قد يتسبب في توسع متكرر بلا حدود للمتغيرات في قوائم الطول المتزايد باستمرار. بمجرد أن نختار Employee, ، أي مرتبطة Project يتم استرداده عبر designer/3 أو developer/3 (ترك نقاط الاختيار) ، حتى جديد Project لم يتم تجميعها بعد ، وفي الوقت الذي نذهب فيه للبحث عن المزيد ؛ حتى لم يعد هناك أي وقت مضى ، وفي هذه الحالة نتوقف (البند الثاني هو الحالة الأساسية).

على الرغم من أن هذا ربما يكون غير فعال بالنسبة إلى أي تنفيذ داخلي (أي ، الأصلي ، غير التفسير) findall, setof أو bagof, ، يعمل على إظهار نهج يهدف إلى مساعدتك في فهم الحل باستخدام طرق التراكم.

إذا كنت بحاجة إلى استخدام All-Solutions مدمج ، فيمكنك التنفيذ projects_of_all/2 كما:

% projects_of_all(List of Staff, List of Projects)
projects_of_all(Employees, Projects):- 
    findall(Project, 
        (   member(Employee, Employees), 
            (   designer(Project, Employee, _)
            ;   developer(Project, Employee, _)
            )
        ), ProjectsBag),
    sort(ProjectsBag, Projects).

لاحظ أن setof و bagof سوف تتراجع لإعطائك بدائل ، لكنك تريد أن تتراكم جميع المشاريع في قائمة ، وهو سلوك findall. من المفترض ، رغم ذلك ، لا تريد التكرارات ، لذا اتصل sort/2 على النتيجة كما هو موضح يزيل التكرارات لإعطائك مجموعة.

تعديل: تغير OP (موضح) السؤال بعد أن كتبت هذا ، والذي دعا إلى إجابة مختلفة تمامًا (التفسير أدناه):

% projects_of_all(List of Staff, List of Projects)
projects_of_all(Employees, CommonProjects):- 
    % find the projects of every employee in the input list
    employee_projects(Employees, EmployeeProjects),
    % find the intersection of all projects (common projects)
    recursive_val_intersect(EmployeeProjects, CommonProjects).

employee_projects([], []).
employee_projects([Employee|Employees], [Projects|Rem]) :-
    findall(Project, 
        (   designer(Project, Employee, _)
        ;   developer(Project, Employee, _)
        ),
    ProjectsBag),
    sort(ProjectsBag, Projects),
    employee_projects(Employees, Rem).

recursive_val_intersect([L|Ls], Intersect) :-
    recursive_val_intersect(Ls, L, Intersect).
recursive_val_intersect([], Acc, Acc).
recursive_val_intersect([L0|Ls], L1, Intersect) :-
    intersection(L0, L1, NewL),
    recursive_val_intersect(Ls, NewL, Intersect).

employee_projects/2 يستخدم لإنشاء قائمة بقوائم المشاريع التي كل منها Employee في قائمة المدخلات عملت عليها. لاحظ أنه يستخدم findall/3 إستراتيجية الحل التي استخدمتها سابقًا. المسند الثاني ، recursive_val_intersect/2,3, ، يحدد تقاطع جميع قوائم المشروع ، حيث يشير هذا إلى المشاريع التي لدى كل موظف عملت معا. هذا يختلف عن الحل أعلاه الذي يبحث فقط عن جميع المشاريع التي يعمل عليها جميع الموظفين في قائمة الإدخال ، وهو ما أهدف إليه.

لاحظ أن recursive_val_intersect/3 يعتمد أعلاه على مسند SWI-prolog intersection/3, ، والتي تأخذ قوائم بدون تكرارات (وبالتالي استخدام sort/2 لبناء قوائم الإدخال في employee_projects/2).

نصائح أخرى

جرب شيئًا مشابهًا لهذا ، حيث Es هي قائمة الموظفين:

setof(P, E^(member(E, Es), employee(P, E)), Projects)

ال E^ هو الكمية الوجودية.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top