繁体   English   中英

从 prolog 谓词中获取多个答案

[英]Get multiple answers from prolog predicate

假设我有一个谓词有时会给我多个输出。 像这样 -

foo(Number, Out) :- Number < 10, Out = less_than_ten.
foo(Number, Out) :- Number > 0, Out = more_than_zero.

我怎么可能会得到所有的值保持为Outfoo在另一个谓词给人铭记它有时可以给一个有时会给多个(列表中的EG)?

编辑 - 不太确定我得到的答案回答了我的问题,所以我会更具体。 根据上述谓词,我可以运行查询foo(5, Out). 这满足两个规则,所以如果我在 SWI-prolog 中运行它,我会得到这个 -

?- foo(5, Out).
Out = less_than_ten

然后我可以输入一个分号让 prolog 回溯并寻找其他解决方案 -

?- foo(5, Out).
Out = less_than_ten ;
Out = more_than_zero.

所以如果我在另一个中执行这个谓词,我如何获得 Out 的所有有效值,给定 Number = 5?

如果您只考虑整数,您可以选择使用 CLP(FD)。 那么你的谓词 foo 可能看起来像这样:

:- use_module(library(clpfd)).

foo(Nums) :-
   Nums ins 1..9.     % the numbers in the list Nums are 0 < X < 10

您可以使用此谓词来测试数字列表是否在您想要的范围内:

   ?- foo([1,2,3,4,5]).
yes
   ?- foo([0,1,2,3,4,5]).
no
   ?- foo([1,2,3,4,5,10]).
no

如果您想使用它来生成该范围内的整数列表,您必须确保Nums是一个列表,以避免实例化错误。 您可以通过在查询中添加目标长度/2 来实现:

   ?- length(Nums,_), foo(Nums).
Nums = [] ? ;          % <- no number
Nums = [_A],           % <- one number
_A in 1..9 ? ;
Nums = [_A,_B],        % <- two numbers
_A in 1..9,
_B in 1..9 ? ;
Nums = [_A,_B,_C],     % <- three numbers
_A in 1..9,
_B in 1..9,
_C in 1..9 ?
.
.
.

这些答案包括剩余目标(有关详细信息,请参阅CLP(FD) 文档)。 如果您想查看实际数字,您必须添加一个目标来标记列表:

   ?- length(Nums,_), foo(Nums), label(Nums).
Nums = [] ? ;
Nums = [1] ? ;
Nums = [2] ? ;
Nums = [3] ? ;
.
.
.
Nums = [1,1] ? ;
Nums = [1,2] ? ;
Nums = [1,3] ? ;
.
.
.
Nums = [9,9] ? ;
Nums = [1,1,1] ? ;
Nums = [1,1,2] ? ;
.
.
.

首先,谓词可以成功或失败。

技术性更强,并在Prolog 标准中进行了说明

在Prolog中,您将电话视为执行。

执行是试图满足一个目标的一系列激活。

在Prolog中,您所认为的回报是:

如果BP激活成功,则将当前CCG激活器替换为激活器true,其激活描述于(7.8.1.1 .1)。

因此,通过将状态压入和弹出到堆栈上来传递值。

为简单起见,我什至会使用更通用的编程术语(调用,传递,参数),甚至认为它们不是用于描述Prolog操作方式的技术上正确的术语。

bar调用foo ,以便bar可以将值传递给foo ,如下所示:

bar :-
    foo(Passed_to_foo).

foo(Received_from_bar) :-
    % Do something with Received_from_bar.

要扩展前一个并将值从foo传递回bar将像这样:

bar :-
    foo(Passed_to_foo,Received_from_foo).

foo(Received_from_bar,Passed_to_bar) :-
     % Do something with Received_from_bar
     % Generate/Compute Passed_to_bar

如果您不知道该参数是否将不包含任何项目,一个项目或一个或多个项目,那么您在考虑列表时是正确的,但是列表也可以同时执行全部三个操作。

要不传递任何值作为列表,只需传递一个空列表

[]

要在列表中传递一个值,只需将其放在列表中并传递列表即可

[first_value]

要传递多个值,只需将它们放在列表中并传递列表

[first_value, second_value, third_value, ... ]

由于这些值将始终在列表中,因此只需使用良好的旧递归来处理列表中的项目即可。

基本情况

foo([],Result).

递归案例

foo([H|T],Result) :-
    % Do something with head of list `H`
    % Pass tail of list `T` back to foo for processing
    foo(T,Result).

刚刚找到了回答这个问题的谓词。 Prolog 有一个内置谓词bagof(Template, Goal, Bag) ,它将Goal谓词的Template参数与Bag参数统一起来(不确定这是正确的 prolog 行话!)。 所以在问题的例子中,使用bagof(Out, foo(5, Out), Outputs). ,这将统一OutOutputs的解决方案列表。 在 SWI-prolog 中运行查询:

4 ?- bagof(Out, foo(5, Out), Outputs).
Outputs = [less_than_ten, more_than_zero].

一个有用的指南,以不同的方式找到一个目标的所有解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM