我编写了一个简单的程序,尝试使用符合特定约束的元素填充给定长度的列表。
例如,我想创建一个包含0到9之间4个整数的列表,其中至少包含3
和4
。我可以想到几个(数千个,真的)这样的列表:
[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).
答案 0 :(得分:5)
我想用一个指向logical-purity的短指针来补充Daniel的答案:
通过regia 到普通的Prolog程序是使用满足您期望的逻辑关系属性的谓词。这种谓词称为纯和单调。
例如,在您的特定情况下,您使用的是非单调谓词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,我建议保持其纯粹和单调的子集。这为可以在各个方向使用的关系铺平了道路。
答案 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] .