插入开放式列表而不绑定其tail变量

时间:2018-11-29 03:43:25

标签: list prolog instantiation-error

是否可以解决Prolog中的以下问题?

AB为数字列表,让N为数字。已知B的降序排列。检查是否可以将N插入A中,使结果为B,但不要绑定任何在A或{{1}中作为尾部出现的变量}。

例如

B

有人可以帮助我吗? :)

编辑1:这就是我想出的。

?- insertable(34, [78, 72, 11 | Z], [78, 72, 34, 11 | Z]).
true. 

?- insertable(34, [78, 72, 11 | Z], L).
L = [78, 72, 34, 11 | Z].

但是,即使在完全实例化参数时按预期方式工作,它也会绑定位于尾部的变量:

insertable(X, List1, List2):- select(X, List2, List1), sorted(List2).

sorted([]).
sorted([_]).
sorted([X, Y | Rest]) :-
  X > Y,
  sorted([Y | Rest]).

编辑2:这是我尝试过的另一种方法。

?- insertable(11, [5, 3, 2], [11, 5, 3, 2]).
true .

?- insertable(11, [5, 3, 2 | X], [11, 5, 3, 2 | X] ).
X = [] .

?- insertable(11, [5, 3, 2 | X], L ).
X = [],
L = [11, 5, 3, 2] .

问题仍然存在:

in(X, [], [X]).
in(X, [Head | Tail1], [Head | Tail2]) :-
  X =< Head,
  in(X, Tail1, Tail2).
in(X, [Head | Tail], [X, Head | Tail]) :-
  X > Head.

1 个答案:

答案 0 :(得分:2)

此练习的窍门是形容词谓词var/1nonvar/1,无论自变量是否为变量,它们都是正确的(也请参阅ground/1,{{1} }和atom/1)。有所作为有点笨拙,因为我们需要将列表integer/1放在头部,并在知道它是否为变量之后统一。

您可能还会感到困惑的是算术比较的错误消息。为此,两个论点都必须扎根。当您不测试尾部是否不变时,统一会自动使用L1实例化尾部。这总是会导致比较[Head|Tail1],从而导致您遇到错误。

以下代码假定您还希望插入尾部闭合的列表。如果没有,则需要删除第一条规则。

number <= Head

测试时,我们可以在变量尾部前面插入1(在第一个结果之后,仍有要测试的路径,但都失败了,在继续查询后会导致in(X, L1, [X]) :- % terminal case for empty list (i.e. tail is not a variable) nonvar(L1), L1 = []. in(X, Xs, [X | Xs]) :- % terminal case if the tail is a variable var(Xs). in(X, L1, [N | Zs]) :- % recursive case X =< N nonvar(L1), L1 = [N | Ys], X =< N, in(X, Ys, Zs). in(X, L1, [X, N | Ys]) :- % recursive case X > N nonvar(L1), L1 = [N | Ys], X > N. ):

false

此外,插入的元素必须为1,因此该元素将失败:

?- in(1,Xs,Ys).
Ys = [1|Xs] ;
false.

似乎递归可以正确传播到结尾:

?- in(1,Xs,[2|Ys]).
false.

在中间插入也可以:

?- in(1,[3, 2 | Xs], Zs).
Zs = [3, 2, 1|Xs] ;
false.

最后是您之前尝试解决的测试用例:

?- in(2,[3,1 |Xs],Zs).
Zs = [3, 2, 1|Xs].

如果列表中出现变量,那仍然行不通:

?- in(34, [78, 72, 11 | Z], [78, 72, 34, 11 | Z]).
true ;
false.

一种简单的解决方法是用?- in(2,[3,A,1|Xs],Zs). ERROR: Arguments are not sufficiently instantiated ERROR: In: ERROR: [10] 2=<_8374 ERROR: [9] in(2,[_8406,1|_8414],[_8418|_8420]) at ./prolog/so-3.pl:9 ERROR: [8] in(2,[3,_8458|...],[3,_8470|_8472]) at ./prolog/so-3.pl:10 ERROR: [7] <user> Exception: (9) in(2, [_7488, 1|_7496], _7820) ? a 保护比较以获取

integer(N)

但是,我们还应该防止插入的元素为非整数,并且列表的末尾带有递减的整数。另外,在这些情况下,我们可以抛出更好的异常。