Prolog CLPFD 中的整数列表和无限循环
List of integers and infinite loop in Prolog CLPFD
假设我想像这样表示整数:integer:Sign:[FirstDigit,SecondDigit,...]
。例如,42 将表示为 integer:positive:[4,2]
.
我需要一个根据此表示生成整数值的谓词,反之亦然。
这是我想出的:
integer_value_('integer':Sign:[H],E) :-
H in 0..9,
(
Sign = 'positive',
E #= H
;
Sign = 'negative',
E #= -H
).
integer_value_('integer':Sign:[H,I|T],E) :-
H in 0..9,
length([I|T],L),
(
Sign = 'positive',
E #= F + H * 10^L
;
Sign = 'negative',
E #= F - H * 10^L
),
integer_value_('integer':Sign:[I|T],F).
这按预期工作。然而,它有一个不幸的 属性 接受诸如 integer:positive:[0,1]
之类的东西,即在列表的开头前导零。当我使用 integer_value_(I,J), label([J]).
枚举所有可能的整数时,这尤其成问题:带有前导零的整数也会出现。
然后我尝试通过仅对除第一个数字以外的所有数字使用 integer_value_
并对第一个数字使用 integer_value
来更正此问题(请记住,我们需要适应 0 被表示列表仅包含 0):
integer_value('integer':Sign:[H],E) :-
abs(E) #< 10,
abs(E) #> -1,
integer_value_('integer':Sign:[H],E).
integer_value('integer':Sign:[H,I|T],E) :-
H in 1..9,
length([I|T],L),
(
Sign = 'positive',
E #= F + H * 10^L
;
Sign = 'negative',
E #= F - H * 10^L
),
integer_value_('integer':Sign:[I|T],F).
但是现在它的行为不正常。例如,integer_value(I,-19).
returns I = integer:negative:[1, 9]
,但是如果我们要求另一个答案,Prolog 会因为我不明白的原因进入无限循环(它应该说 false,或者已经知道有没有其他答案)。
这个问题不会发生在 "opposite" 查询 integer_value(integer:negative:[1,9],Z).
which returns Z = 19
然后是 false,当两个参数都是变量时也不会发生(它枚举数字正确,没有前导零),这让我感到惊讶。
知道无限循环发生的原因吗?是否有简单的方法来修复它?
要查看问题,查看程序的一小部分就足够了。事实上下面的 failure-slice 就足够了:
integer_value('integer':Sign:[H],E) :- false,
abs(E) #< 10,
abs(E) #> -1,
integer_value_('integer':Sign:[H],E).
integer_value('integer':Sign:[H,I|T],E) :-
H in 1..9,
length([I|T],L), false,
( Sign = 'positive',
E #= F + H * 10^L
;
Sign = 'negative',
E #= F - H * 10^L
),
integer_value_('integer':Sign:[I|T],F).
L
第一次出现在这里,所以任何长度都是可能的。
您将不得不以某种方式修改长度目标。
我设法使用@false
指出的this other answer解决了我的问题
其中一个要点是在最后一步确定数字的符号,这样当遍历可能的整数时,我们会得到正数和负数之间的交替答案:达到 9(1 位)后,它将统一为-9,再统一为-8等,-1之后统一为10、11等,99之后统一为-99、-98等,明白了。
integer_value('integer':Sign:I,E) :-
integer_value('integer':Sign:I,0,E,E).
integer_value('integer':Sign:[H],N0,N,M) :-
H in 0..9,
N1 #= H + N0 * 10,
abs(M) #>= abs(N1),
integer_value_('integer':Sign:[],N1,N,M).
integer_value('integer':Sign:[H,I|T],N0,N,M) :-
H in 1..9,
N1 #= H + N0 * 10,
abs(M) #>= abs(N1),
integer_value_('integer':Sign:[I|T],N1,N,M).
integer_value_('integer':Sign:[],N0,N,_) :-
(
Sign = 'positive',
N #= N0
;
Sign = 'negative',
N #\= 0,
N #= - N0
).
integer_value_('integer':Sign:[H],N0,N,M) :-
H in 0..9,
N1 #= H + N0 * 10,
abs(M) #>= abs(N1),
integer_value_('integer':Sign:[],N1,N,M).
integer_value_('integer':Sign:[H,I|T],N0,N,M) :-
H in 0..9,
N1 #= H + N0 * 10,
abs(M) #>= abs(N1),
integer_value_('integer':Sign:[I|T],N1,N,M).
假设我想像这样表示整数:integer:Sign:[FirstDigit,SecondDigit,...]
。例如,42 将表示为 integer:positive:[4,2]
.
我需要一个根据此表示生成整数值的谓词,反之亦然。
这是我想出的:
integer_value_('integer':Sign:[H],E) :-
H in 0..9,
(
Sign = 'positive',
E #= H
;
Sign = 'negative',
E #= -H
).
integer_value_('integer':Sign:[H,I|T],E) :-
H in 0..9,
length([I|T],L),
(
Sign = 'positive',
E #= F + H * 10^L
;
Sign = 'negative',
E #= F - H * 10^L
),
integer_value_('integer':Sign:[I|T],F).
这按预期工作。然而,它有一个不幸的 属性 接受诸如 integer:positive:[0,1]
之类的东西,即在列表的开头前导零。当我使用 integer_value_(I,J), label([J]).
枚举所有可能的整数时,这尤其成问题:带有前导零的整数也会出现。
然后我尝试通过仅对除第一个数字以外的所有数字使用 integer_value_
并对第一个数字使用 integer_value
来更正此问题(请记住,我们需要适应 0 被表示列表仅包含 0):
integer_value('integer':Sign:[H],E) :-
abs(E) #< 10,
abs(E) #> -1,
integer_value_('integer':Sign:[H],E).
integer_value('integer':Sign:[H,I|T],E) :-
H in 1..9,
length([I|T],L),
(
Sign = 'positive',
E #= F + H * 10^L
;
Sign = 'negative',
E #= F - H * 10^L
),
integer_value_('integer':Sign:[I|T],F).
但是现在它的行为不正常。例如,integer_value(I,-19).
returns I = integer:negative:[1, 9]
,但是如果我们要求另一个答案,Prolog 会因为我不明白的原因进入无限循环(它应该说 false,或者已经知道有没有其他答案)。
这个问题不会发生在 "opposite" 查询 integer_value(integer:negative:[1,9],Z).
which returns Z = 19
然后是 false,当两个参数都是变量时也不会发生(它枚举数字正确,没有前导零),这让我感到惊讶。
知道无限循环发生的原因吗?是否有简单的方法来修复它?
要查看问题,查看程序的一小部分就足够了。事实上下面的 failure-slice 就足够了:
integer_value('integer':Sign:[H],E) :- false,abs(E) #< 10,abs(E) #> -1,integer_value_('integer':Sign:[H],E). integer_value('integer':Sign:[H,I|T],E) :- H in 1..9, length([I|T],L), false,( Sign = 'positive',E #= F + H * 10^L;Sign = 'negative',E #= F - H * 10^L),integer_value_('integer':Sign:[I|T],F).
L
第一次出现在这里,所以任何长度都是可能的。
您将不得不以某种方式修改长度目标。
我设法使用@false
指出的this other answer解决了我的问题其中一个要点是在最后一步确定数字的符号,这样当遍历可能的整数时,我们会得到正数和负数之间的交替答案:达到 9(1 位)后,它将统一为-9,再统一为-8等,-1之后统一为10、11等,99之后统一为-99、-98等,明白了。
integer_value('integer':Sign:I,E) :-
integer_value('integer':Sign:I,0,E,E).
integer_value('integer':Sign:[H],N0,N,M) :-
H in 0..9,
N1 #= H + N0 * 10,
abs(M) #>= abs(N1),
integer_value_('integer':Sign:[],N1,N,M).
integer_value('integer':Sign:[H,I|T],N0,N,M) :-
H in 1..9,
N1 #= H + N0 * 10,
abs(M) #>= abs(N1),
integer_value_('integer':Sign:[I|T],N1,N,M).
integer_value_('integer':Sign:[],N0,N,_) :-
(
Sign = 'positive',
N #= N0
;
Sign = 'negative',
N #\= 0,
N #= - N0
).
integer_value_('integer':Sign:[H],N0,N,M) :-
H in 0..9,
N1 #= H + N0 * 10,
abs(M) #>= abs(N1),
integer_value_('integer':Sign:[],N1,N,M).
integer_value_('integer':Sign:[H,I|T],N0,N,M) :-
H in 0..9,
N1 #= H + N0 * 10,
abs(M) #>= abs(N1),
integer_value_('integer':Sign:[I|T],N1,N,M).