定义谓词Prolog

时间:2016-11-16 13:09:27

标签: prolog clpfd

我正在审查即将进行的测试的一些练习,并且遇到困难。

  

给定一个整数列表L,定义谓词:add(L,S),它返回一个整数列表S,其中每个元素是L中所有元素之和到达相同位置的总和。

     

示例:

     

? - 添加([1,2,3,4,5],S)。

     

S = [1,3,6,10,15]。

所以我的问题是谓词定义的含义是什么?它看起来很一般。我读过一些帖子,但是他们提供的内容并不多。谢谢!

2 个答案:

答案 0 :(得分:4)

这是一个很好的练习,可以熟悉两个重要的Prolog概念:

  • 声明性整数算术以推断所有方向的整数
  • 元谓词缩短您的代码。

我们从一个非常简单的关系开始,将整数I和整数S0与新的S相关联:

sum_(I, S0, S) :- S #= S0 + I.

根据您的Prolog系统,您可能需要一个指令,如:

:- use_module(library(clpfd)).

使用声明性整数运算。

其次,有一个强大的元谓词系列(见)称为scanl/N,在Richard O'Keefe的Prolog library proposal中有描述,并已在某些系统中实施。在我们的例子中,我们只需要scanl/4

示例查询:

?- scanl(sum_, [1,2,3,4,5], 0, Sums).
Sums = [0, 1, 3, 6, 10, 15].

完成!

事实上,更多比完成,因为我们可以在所有方向中使用它,例如:

?- scanl(sum_, Is, 0, Sums).
Is = [],
Sums = [0] ;
Is = [_2540],
Sums = [0, _2540],
_2540 in inf..sup ;
Is = [_3008, _3014],
Sums = [0, _3008, _3044],
_3008+_3014#=_3044 ;
etc.

这是我们对真正关系解决方案的期望!

还要注意0的出现是部分和列表中的第一个元素。它满足您对任务的文本描述,但不满足您发布的示例。我将这些作为练习对齐。

答案 1 :(得分:1)

定义谓词只是意味着编写一个执行问题所需要的谓词。 在您的问题中,您必须编写add / 2谓词的定义(“/ 2”表示它有两个参数)。你可以写下面的定义:

add(L,S):- add1(L,0,S).

add1([],_,[]).
add1([H|T],Sum,[H1|T1]):- H1 is Sum+H,NSum is Sum+H,add1(T,NSum,T1).

上面的谓词为您提供所需的输出。一个简单的例子:

?- add([1,2,3,4,5],S).
S = [1, 3, 6, 10, 15].

我认为上述或类似的谓词是某人在测试中等待的东西。

一些其他信息问题

上面谓词的问题在于,如果您查询例如:

?- add(S,L).
S = L, L = [] ;
ERROR: is/2: Arguments are not sufficiently instantiated

正如您所看到的,当您尝试询问谓词何时成功时,它会提供一个明显的解决方案,并且对于进一步的解决方案,它会引发错误。这不是一个非常好的财产。您可以使用模块CLPFD来改进它:

:- use_module(library(clpfd)).


add(L,S):- add1(L,0,S).

add1([],_,[]).
add1([H|T],Sum,[H1|T1]):- H1 #= Sum+H,NSum #= Sum+H,add1(T,NSum,T1).

现在进行一些查询:

?- add([1,2,3,4,5],S).
S = [1, 3, 6, 10, 15].

?- add(S,[1,3,6]).
S = [1, 2, 3].

?- add(S,L).
S = L, L = [] ;
S = L, L = [_G1007],
_G1007 in inf..sup ;
S = [_G1282, _G1285],
L = [_G1282, _G1297],
_G1282+_G1285#=_G1307,
_G1282+_G1285#=_G1297 ;

...and goes on..

正如您现在所看到的,谓词可以提供您提出的任何信息!那是因为现在它有一个更多的关系行为,而不是之前因is/2谓词而产生的功能行为。 (这些是用于改进谓词行为的更多信息。对于测试,您可能不允许使用库等...因此您可能只编写一个至少回答问题的简单解决方案。)