2

目前,我正在生成一个列表,其中每个元素的值等于前一个元素的平方加上 Z 的值。使用 generate_list 生成列表后,我想检查它是否是有序列表。我已经实现了ordered,然后在控制台中,我试图做一些类似ordered(generate_list(A, B, Z,[]). 的事情,它总是返回false,即使我确定它必须是真的。我知道这种方法在 Prolog 中不好,但我不知道该怎么做......

gen(0,0,_).
gen(N,F,Z) :- X is N-1,gen(X,A,Z),F is (A*A)+Z.

generate_list(A,B,Z,[]):- A>B.
generate_list(A,B,Z,[H|T]):-
    A =< B,
    gen(A,H,Z),
    AA is A + 1,
    generate_list(AA,B,Z,T).

ordered([]).
ordered([_]).
ordered([X,Y|Z]):-X=<Y,ordered([Y|Z]).
4

3 回答 3

3

我真的不明白你为什么gen/3在这里指定一个函数。您可以使用accumulator,因此每次更新累加器,如:

generate_list(N, Z, L) :-
    generate_list(N, Z, 0, L).

generate_list(0, _, _, []).
generate_list(N, Z, A, [A|T]) :-
    N > 0,
    B is A*A + Z,
    N1 is N-1,
    generate_list(N1, Z, B, T).

例如对于Zis 1,我们得到:

?- generate_list(5, 1, L).
L = [0, 1, 2, 5, 26] ;
false.

使用ordered/1您问题中的谓词,我们看到该列表确实是有序的:

?- generate_list(5, 1, L), ordered(L).
L = [0, 1, 2, 5, 26] ;
false.

而对于Z = -1,它不是:

?- generate_list(5, -1, L).
L = [0, -1, 0, -1, 0] ;
false.

?- generate_list(5, -1, L), ordered(L).
false.
于 2019-05-16T19:44:16.850 回答
1

要扩展之前的答案,特别是 Willem Van Onsem 的答案,您可以编写如下内容:

my_ord(P,L):- 
    call(P,L),
    ordered(L).

然后您可以查询?- my_ord(generate_list(5, 1),L). 要删除选择点,您可以once/1同时使用call/2andordered/1或编写另一个谓词,例如my_ord_(P,L):- once(my_ord(P,L))或放置 cut !。考虑到 Willem Van Onsem 的回答,您需要在generate_list(0, _, _, []). 在您的ordered/1 中,您需要在 and 之后进行ordered([])切割 ordered([_])

于 2019-05-17T07:51:13.730 回答
1

ordered/1可能按原样工作。但它留下了一个选择点!你可以使用once( sorted(L) ).

“有序”有点类似于“排序”,不是吗?

如果列表中有重复项,请使用msort

sorted(L) :- msort(L, L).

如果您不允许重复,请使用sort

sorted_uniq(L) :- sort(L, L).

两者都没有留下选择点。

这为您留下了另一个答案中的解决方案留下的选择点。你可以列一个清单,然后把它填满。

generate_list(N, Z, L) :-
    length(L, N),
    generate_list_1(L, Z, 0).

generate_list_1([], _, _).
generate_list_1([X|Xs], Z, X) :-
    X1 is X^2 + Z,
    X1 >= X, % Checks for order!
    generate_list_1(Xs, Z, X1).

这个实现只会给你增加列表,不会留下不必要的选择点。

于 2019-05-17T07:17:41.057 回答