我编写了一个简单的程序来尝试使用满足特定约束的元素填充给定长度的列表.
例如,我想创建一个包含0到9之间的4个整数的列表,其中至少包含3
和4
.我可以想到几个(数千个,真的)这样的列表:
[3,4,0,0]
[0,3,4,0]
[3,1,9,4]
etc...
Run Code Online (Sandbox Code Playgroud)
但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).
Run Code Online (Sandbox Code Playgroud)
并运行我描述的示例:
?- filled_list([3,4], is_single_digit_integer, 4, X).
Run Code Online (Sandbox Code Playgroud)
我想用一个简短的指向逻辑纯度的指针来补充Daniel的答案:
通用Prolog程序的via regia是使用满足您期望的逻辑关系属性的谓词.这种谓词被称为纯粹和单调.
例如,在您的特定情况下,您使用的是非单调谓词integer/1
和is_list/1
.如果你改为使用可以在所有方向上使用的谓词,你的问题就会完全消失,例如:
is_single_digit_integer(N) :- N in 0..9.
这使用clpfd约束(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,我建议保持其纯粹和单调的子集.这为可以在所有方向上使用的关系铺平了道路.