函数在prolog中查找列表

函数在prolog中查找列表,prolog,Prolog,我是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 = []

我是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表示我希望输出为遵循规则且不为false的列表的列表。您能帮我找到如何解决这个问题,并在这些情况下为输出创建一个列表吗?

使用未绑定列表的谓词失败的直接原因是您使用了
->
构造来控制流

下面是您尝试执行的操作的简化版本,一个用于检查列表是否为空的小谓词:

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.
突然,只有空列表被接受,尽管我们从上面知道非空列表也可以

这是因为
->
一旦发现其条件得到满足,就会删除任何备选方案。在上一个示例中,
列表
是一个变量,因此它可以与
[]
统一。条件
列表=[]
将成功(将
列表
绑定到
[]
),备选方案
列表=[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>
?-sum2(X,0,13)。
错误:参数没有充分实例化
错误:在:
错误:[9]_2416是0+_2428*。。。
错误:[8]sum2[u 2462],0,13)位于/home/gergo/sum.pl:5
错误:[7]

您正在尝试对
H
进行算术运算,该运算没有任何值。如果要使用“plain”Prolog算术,在尝试对其执行算术之前,您需要枚举
H
可能具有的适当值。或者,您可以使用算术约束。请参阅在处的两种可能实现。

使用未绑定列表的谓词失败的直接原因是由于您使用了
->控制流的构造

下面是您尝试执行的操作的简化版本,一个用于检查列表是否为空的小谓词:

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.
突然,只有空列表被接受,尽管我们从上面知道非空列表也可以

这是因为
->
一旦发现其条件得到满足,就会删除任何备选方案。在上一个示例中,
列表
是一个变量,因此它可以与
[]
统一。条件
列表=[]
将成功(将
列表
绑定到
[]
),备选方案
列表=[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>
?-sum2(X,0,13)。
错误:参数没有充分实例化
错误:在:
错误:[9]_2416是0+_2428*。。。
错误:[8]sum2[u 2462],0,13)位于/home/gergo/sum.pl:5
错误:[7]

您正在尝试对
H
进行算术运算,该运算没有任何值。如果要使用“plain”Prolog算术,在尝试对其进行算术之前,您需要枚举
H
可能具有的适当值。或者,您可以使用算术约束。请参阅在处的两种可能实现。

这几乎是的重复。但是表示法很奇怪。例如,如果您要表示
N=16
使用
K=1
2的幂,在你的位置符号中对应的列表是什么?你可以说它是
[1,0,0,0,1]
(1*16,0*8,0*4,0*2,0*1)。但这给出了一个长度为0的列表