在Prolog中使用And /或

时间:2017-01-07 17:53:18

标签: prolog

所以我对prolog相对较新,我在互联网上遇到了一些可用于表示And / Or节点的代码。

% a is an or node with successors b,c,d.
or(a,[b,c,d]).
% c is an and node with successor d,e,f.
and(c,[d,e,f]).
% d is a terminal (solvable) node.
goal(d).

我很困惑这个谓词如何用于查找可解决的节点。 并指出我指向正确的方向将是奇妙的

2 个答案:

答案 0 :(得分:2)

您似乎已经从东英吉利大学计算机科学系主要系列UG考试2013/14中找到问题2(c)(在Google上使用引用的文字搜索找到),询问:

  

给定由一组Prolog子句指定的AND / OR树

% a is an or node with successors b,c,d.
or(a,[b,c,d]).
% c is an and node with successor d,e,f.
and(c,[d,e,f]).
% d is a terminal (solvable) node.
goal(d).
     

编写一个Prolog程序,其主要子句solve(X)仅在X可解决的情况下成功。

作为背景:

  • 当且仅当所有后继者都可以解决时,它才是可解决的。
  • 当且仅当至少有一个后继者可以解决时,or-node才是可解决的。
  • 如果终端节点是目标,则它是可解决的。

请求的Prolog程序看起来像这样:

%not necessary - without this solve_and([]) will be false anyway
solve_and([]) :- 
    false.

solve_and([H]) :- 
    solve(H).

solve_and([H|T]) :-
    solve(H),
    solve_and(T).

%not necessary - without this solve_or([]) will be false anyway
solve_or([]) :-
    false.

solve_or([H|T]) :-
    solve(H);
    solve_or(T).

solve(X) :-
    goal(X),
    !.

solve(X) :-
    and(X, A),
    solve_and(A),
    !.

solve(X) :-
    or(X, A),
    solve_or(A),
    !.

从消费者的角度来看,这很有效 - 一个用X调用解决方案来检查是否正确,但是切割(!)使它成为可解决的X的不良生成器。从解决规则中删除剪切应该使系统成为双向的。

答案 1 :(得分:2)

此特定问题要求您编写谓词以确定给定节点是否可解。换句话说,如果您要查询solve(z),它会成功还是失败,具体取决于z是否可以解决。

首先要写出规则是什么。 Jim Ashworth已经在答案中做到了这一点,但我会在这里重申一下:

  • 规则1:如果节点X是目标,则节点X是可解决的
  • 规则2:如果X是一个或多个可解决的节点的连接(和),则节点X是可解的
  • 规则3:如果X是一个或多个节点的分离(或),其中至少有一个节点是可解的,则节点X是可解的

让我们先简单地在Prolog中写一下。

% Rule 1
solve(X) :- goal(X).

% Rule 2
solve(X) :-
    and(X, Subgoals),
    all_solvable(Subgoals).

% Rule 3
solve(X) :-
    or(X, Subgoals),
    at_least_one_solvable(Subgoals).

现在我们需要编写谓词all_solvable/1at_least_one_solvable/1

% Auxiliary predicates used above

all_solvable([]).
all_solvable([Node|Nodes]) :-
    solve(Node),
    all_solvable(Nodes).

at_least_one_solvable([Node]) :- solve(Node).
at_least_one_solvable([Node, NextNode|Nodes]) :-
    (   solve(Node)
    ->  true
    ;   at_least_one_solvable([NextNode|Nodes])
    ).

你可以看到这几乎与吉姆的答案相同,这完全是正确的方向。我只是从Prolog的角度提供了一些改进。出于这个原因,我认为Jim值得称赞答案。除了我选择的谓词名称之外,差异是:

  • 我省略了绝对失败的目标,因为它是多余的
  • 我使用p1 -> p2 ; p3构造来处理"成功一次"对于析取案件
  • 即使没有子目标(最常见的解决方案),all_solvable/1也会成功
  • 我避免削减否则允许一般解决方案发生

在上方,p1 -> p2 ; p3构造的行为与p1, !, p2 ; p3相同。因此,对于某些情况,正如Jim在他的评论中指出的那样,削减是有帮助的,你只是在这个问题中寻找可解决性,而不是多种可解决方式。您还可以找到一种方法来使用once/1谓词来实现此目的(您可以将其视为练习)。

all_solvable/1的替代实现:

all_solvable(Goals) :- maplist(solve, Goals).

此时,maplist(solvable, Goals)将成功,且仅当solvable成功Goals列表的每个元素时才会成功。

与Jim的解决方案一样,这将告诉您具体目标是否可以解决(尽管Jim的答案不会像我的解决方案那样留下选择点):

| ?- solve(a).

true? ;

no
| ?-

上述解决方案的另一个好处是,它可以使用所有正确的解决方案正确回答常规查询:

| ?- solve(X).

X = d ? ;

X = a ? ;

no
| ?-