我的Prolog"列表填充符"有什么问题?

时间:2017-09-19 19:02:18

标签: prolog

我编写了一个简单的程序,尝试使用符合特定约束的元素填充给定长度的列表。

例如,我想创建一个包含0到9之间4个整数的列表,其中至少包含34。我可以想到几个(数千个,真的)这样的列表:

[3,4,0,0]
[0,3,4,0]
[3,1,9,4]
etc...

但SWI Prolog只返回false。我只是犯了某种逻辑错误,还是我使用Prolog错了?

我的代码:

is_single_digit_integer(N) :-
  integer(N),
  between(0, 9, N).

filled_list(Given, FillConstraint, OutLen, Out) :-
  is_list(Out),
  length(Out, OutLen),
  length(Given, GivenLen),
  between(0, OutLen, GivenLen),
  maplist(FillConstraint, Out),
  subset(Given, Out).

运行我描述的例子:

?- filled_list([3,4], is_single_digit_integer, 4, X).

2 个答案:

答案 0 :(得分:5)

我想用一个指向的短指针来补充Daniel的答案:

通过regia 到普通的Prolog程序是使用满足您期望的逻辑关系属性的谓词。这种谓词称为单调

例如,在您的特定情况下,您使用的是非单调谓词integer/1is_list/1。如果使用可在所有方向中使用的谓词,则问题会完全消失,例如:

is_single_digit_integer(N) :-
  N in 0..9.

这使用约束(in)/2来声明:N是0到9之间的整数

适用于以下所有情况:

?- is_single_digit_integer(N).
N in 0..9.

?- is_single_digit_integer(3).
true.

?- is_single_digit_integer(20).
false.

相反,integer/1 不完整

?- integer(N).
false.

→不存在整数??

同样适用于is_list/1,对于最常见的查询来说已经非常短暂了:

?- is_list(Ls).
false.

相反,要说明Ls是一个列表,您可以使用:

length(Ls, _)

这是否正常是否实例化 Ls。例如:

?- length(Ls, _).
Ls = [] ;
Ls = [_6650] ;
Ls = [_6650, _6656] ;
Ls = [_6650, _6656, _6662] ;
etc.

为了充分利用Prolog,我建议保持其纯粹和单调的子集。这为可以在各个方向使用的关系铺平了道路。

答案 1 :(得分:4)

integer(N)is_list(Out)都假定绑定变量并且对未实例化的变量失败。解决方案是删除它们:

is_single_digit_integer(N) :-
  between(0, 9, N).

filled_list(Given, FillConstraint, OutLen, Out) :-
  length(Out, OutLen),
  length(Given, GivenLen),
  between(0, OutLen, GivenLen),
  maplist(FillConstraint, Out),
  subset(Given, Out).

你现在可以看到它有效:

?- filled_list([3,4], is_single_digit_integer, 4, X).
X = [0, 0, 3, 4] ;
X = [0, 0, 4, 3] ;
X = [0, 1, 3, 4] ;
X = [0, 1, 4, 3] .

我认为您正在尝试使用这些谓词,就好像它们是类型约束一样,但Prolog只是不能那样工作。相信你的类型,一切都会好的;毕竟,between除了整数之外不会给你任何东西,length除了列表之外不会给你任何东西。

奖金技巧:

?- filled_list([3,4], between(0,9), 4, X).
X = [0, 0, 3, 4] ;
X = [0, 0, 4, 3] ;
X = [0, 1, 3, 4] ;
X = [0, 1, 4, 3] ;
X = [0, 2, 3, 4] .