在prolog中查找列表的函数

问题描述 投票:1回答:1

我是Prolog的新手,我想写一个函数来找到一个遵循某些规则的列表。更具体地说,给定两个数字N和K,我想让我的函数找到一个列表,其中有K个2的幂,它们的和是N。例如,如果N=13,K=5,我希望我的列表是[2,2,1],其中第一个2表示两个4,第二个2表示两个2,第三个1表示一个1(4+4+2+2+1=13)。考虑到从列表的末尾开始,每个位置i代表2^i的2次方,所以我写了这样的代码。

sum2(List, SUM, N) :-
   List = []  -> N=SUM;
   List = [H|T],
   length(T, L),
   NewSUM is SUM + (H * 2**L),
   sum2(T, NewSUM, N).

powers2(N,K,X):-
   sum2(X,0,N),
   sum_list(X, L),
   K = L.

问题是:

?- sum2([2,2,1],0,13).
true.
?- sum2([2,2,1],0,X).
X = 13.
?- sum2(X,0,13).
false.
?- powers2(X,5,[2,2,1]).
X = 13.
?- powers2(13,5,[2,2,1]).
true.
?- powers2(13,X,[2,2,1]).
X = 5.
?- powers2(13,5,X).
false.

在这些情况下,X代表列表 我希望输出的是一个遵循规则的列表,而不是虚假的。你能帮助我找到如何解决这个问题,并在这些情况下有一个列表的输出?

prolog swi-prolog logic-programming
1个回答
0
投票

你的谓词在非约束列表中失败的直接原因是由于你使用了 -> 控制流的构造。

这是一个简化的版本,你要做的是一个用于检查列表是否为空的小谓词。

empty_or_not(List, Answer) :-
    (   List = []
    ->  Answer = empty
    ;   List = [H|T],
        Answer = head_tail(H, T) ).

(附注: 确切的布局是一个品味问题, 但你应该把它作为一个小的前提条件. 始终 如果您使用的是 ; 运营商。我也敦促你 从来没有; 在线条的末端,而是在一个真正突出的位置。使用 ; 在Prolog中确实是个特例,如果它的格式太类似于 ,这很难看出它的存在,也很难看出它适用于句子的哪些部分)。)

这似乎是可行的,对吗?

?- empty_or_not([], Answer).
Answer = empty.

?- empty_or_not([1, 2, 3], Answer).
Answer = head_tail(1, [2, 3]).

好吧,到目前为止,但如果我们用一个未绑定的列表来调用这个函数呢?

?- empty_or_not(List, Answer).
List = [],
Answer = empty.

突然间只有空列表被接受了,虽然我们 知道 从上面来看,非空列表也是可以的。

这是因为 -> 一旦发现其条件得到满足,就会切断任何替代方案。在最后一个例子中: List 是一个变量,所以它与 []. 状况 List = [] 会成功 List[]),另一种是 List = [H|T] 不会去尝试。看似简单,但 -> 是Prolog的一个高级功能。它只应该由更有经验的用户来使用,因为他们知道他们真的不需要探索替代方案。

在Prolog中,通常,也是正确的,实现反结的方式是为不同的情况使用不同的子句。

empty_or_not([], empty).
empty_or_not([H|T], head_tail(H, T)).

现在这样做是符合逻辑的

?- empty_or_not([], Answer).
Answer = empty.

?- empty_or_not([1, 2, 3], Answer).
Answer = head_tail(1, [2, 3]).

?- empty_or_not(List, Answer).
List = [],
Answer = empty ;
List = [_2040|_2042],
Answer = head_tail(_2040, _2042).

相应地,你的定义是 sum2 应该更像这样。

sum2([], SUM, N) :-
    N = SUM.
sum2([H|T], SUM, N) :-
    length(T, L),
    NewSUM is SUM + (H * 2**L),
    sum2(T, NewSUM, N).

然而,这只是一小步

?- sum2(X, 0, 13).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR:    [9] _2416 is 0+_2428* ...
ERROR:    [8] sum2([_2462],0,13) at /home/gergo/sum.pl:5
ERROR:    [7] <user>

你是在尝试对 H,它没有值。如果你想使用 "普通 "的Prolog算术,你将需要枚举适当的值,这些值就是 H 在你尝试对其进行运算之前,可能会有。另外,你也可以使用算术约束。查看这两种方法的可能实现 Prolog中的算术学,用2的幂来表示一个数字.

© www.soinside.com 2019 - 2024. All rights reserved.