选择点修剪需要削减,但我认为编译器应该足够敏锐,可以自行完成
Choicepoint pruning needs a cut, but I think the compiler should be sharp enough to do it by itself
我正在做一个练习,写一个需要额外步长值的 between/3
。
这是一个有趣的练习,快速显示:
- 标记整数的优势(即如果
X
是正整数以利用模式匹配,则使用 pos(X)
而不是 X
)
- 使谓词尽可能具有确定性的内在魔力(不要在序列末尾留下一个开放的选择点)
- 将 "flag" 数组传递给谓词以微调行为的兴趣(在这种情况下,如果序列为空,它应该抛出还是失败?)
还有:
- ISO 标准例外条款的格式不够深思熟虑(使用复合条款而不是列表来传递信息......WTF!)
library(error)
中异常抛出谓词的命名(为什么不叫它们throw_...
而不是混淆地给它们与异常术语相同的名称,人们真的会想要call(domain_error(...))
?
- 事实上
must_be/2
无法获取关于哪个 arg 确切导致问题的附加位置信息(为什么!)
完整的代码是 between_with_step.pl ... 还没有完全单元测试。
现在我已经设置了以下谓词
between_enum(+Start,+TaggedEnd,+TaggedStep,-Value)
发出递增或递减整数序列的下一个值。它使用标记值的模式匹配。特别是,"end value if the sequence is an integer"(与表示 无穷大 的原子相反)和 "the step is positive" 的情况由以下与术语 [=26= 匹配的子句子集给出] 和 pos(Step)
:
% ---
% Case of "positive step" pos(Step) and "integer end" int(End) (not infinite end)
% ---
% Past end of sequence. Occurs only if the sequence is empty on entry.
between_enum(Start,int(End),pos(_),_) :-
Start > End,!,fail.
% Last entry in sequence, emit "Start" as "Value" and don't allow backtracking!
% The test "Start < End" is redundant here.
between_enum(Start,int(End),pos(Step),Start) :-
Start < End, Start+Step > End, !.
% More entries exist in sequence, emit "Start" as "Value" and DO allow backtracking!
% The test "Start < End" is redundant here.
% The test "Start+Step =< End" is redundant here, being the complement of the cut-off preceding clause
between_enum(Start,int(End),pos(Step),Start) :-
Start < End, Start+Step =< End.
% Recursive alternative to the above, digging for more values!
% The test "Start < End" is redundant here.
% The test "Start+Step =< End" is redundant here
between_enum(Start,int(End),pos(Step),Value) :-
Start < End, Start+Step =< End,
NewStart is Start+Step,
%!, % NEEDED TO MAINTAIN DETERMINACY ON LAST VALUE
between_enum(NewStart,int(End),pos(Step),Value).
现在,为了在枚举结束时完全确定,以下子句需要删减:
between_enum(Start,int(End),pos(Step),Value) :-
Start < End, Start+Step =< End,
NewStart is Start+Step,
!, % <---- HERE
between_enum(NewStart,int(End),pos(Step),Value).
否则:
有剪裁:
?- between(10,15,1,Value).
Value = 10 ;
Value = 11 ;
Value = 12 ;
Value = 13 ;
Value = 14 ;
Value = 15. % This is the end for sure!
没有剪切:
?- between(10,15,1,Value).
Value = 10 ;
Value = 11 ;
Value = 12 ;
Value = 13 ;
Value = 14 ;
Value = 15 ; % Unsure whether this is the end?
false. % Well, turns out it is the end, really!
编译器不应该足够强大来确定在 between_enum(Start,int(End),pos(Step),Value)
之后没有进一步的匹配是可能的 - 这是标记为
的系列中的最后一个
int/1
在第二位和
pos/1
第三名?
这个 SWI-Prolog 8.1.
编辑
可能是编译器只索引了前两个参数。不需要切入
between_enum(Start,int(End),neg(Step),Value)
后面只有
between_enum(Start,inf,neg(Step),Value)
以及
between_enum(Start,minf,neg(Step),Value)
所以它可以很好地区分 inf
、minf
和 int(_)
。
你对参数顺序的直觉是正确的,可以通过一个简单的实验来证实。
first(tag1(_),_).
first(tag2(_),_).
second(_,tag1(_)).
second(_,tag2(_)).
?- first(tag1(1),2).
true.
?- second(2,tag1(1)).
true ;
false.
这是 Prolog 系统相关的,并且取决于可用的自动索引或可用的索引指令。例如 SWI-Prolog 有自动深度索引,但有一些关于自动多参数索引的特性。所以对于来自 madgen 的例子:
first(tag1(_),_).
first(tag2(_),_).
second(_,tag1(_)).
second(_,tag2(_)).
我进入我的系统,两个查询都不留选择点:
Jekejeke Prolog 4, Runtime Library 1.4.7
?- first(tag1(1),2).
Yes
?- second(2,tag1(1)).
Yes
另一方面,在SWI-Prolog中,第二个查询中留下了一个选择点:
SWI-Prolog (threaded, 64 bits, version 8.3.17)
?- first(tag1(1),2).
true.
?- second(2,tag1(1)).
true ;
false.
这可能会很烦人,而且经常需要使用外观谓词
用于重新排序参数,使它们更适合
SWI-Prolog 特定索引。
我正在做一个练习,写一个需要额外步长值的 between/3
。
这是一个有趣的练习,快速显示:
- 标记整数的优势(即如果
X
是正整数以利用模式匹配,则使用pos(X)
而不是X
) - 使谓词尽可能具有确定性的内在魔力(不要在序列末尾留下一个开放的选择点)
- 将 "flag" 数组传递给谓词以微调行为的兴趣(在这种情况下,如果序列为空,它应该抛出还是失败?)
还有:
- ISO 标准例外条款的格式不够深思熟虑(使用复合条款而不是列表来传递信息......WTF!)
library(error)
中异常抛出谓词的命名(为什么不叫它们throw_...
而不是混淆地给它们与异常术语相同的名称,人们真的会想要call(domain_error(...))
?- 事实上
must_be/2
无法获取关于哪个 arg 确切导致问题的附加位置信息(为什么!)
完整的代码是 between_with_step.pl ... 还没有完全单元测试。
现在我已经设置了以下谓词
between_enum(+Start,+TaggedEnd,+TaggedStep,-Value)
发出递增或递减整数序列的下一个值。它使用标记值的模式匹配。特别是,"end value if the sequence is an integer"(与表示 无穷大 的原子相反)和 "the step is positive" 的情况由以下与术语 [=26= 匹配的子句子集给出] 和 pos(Step)
:
% ---
% Case of "positive step" pos(Step) and "integer end" int(End) (not infinite end)
% ---
% Past end of sequence. Occurs only if the sequence is empty on entry.
between_enum(Start,int(End),pos(_),_) :-
Start > End,!,fail.
% Last entry in sequence, emit "Start" as "Value" and don't allow backtracking!
% The test "Start < End" is redundant here.
between_enum(Start,int(End),pos(Step),Start) :-
Start < End, Start+Step > End, !.
% More entries exist in sequence, emit "Start" as "Value" and DO allow backtracking!
% The test "Start < End" is redundant here.
% The test "Start+Step =< End" is redundant here, being the complement of the cut-off preceding clause
between_enum(Start,int(End),pos(Step),Start) :-
Start < End, Start+Step =< End.
% Recursive alternative to the above, digging for more values!
% The test "Start < End" is redundant here.
% The test "Start+Step =< End" is redundant here
between_enum(Start,int(End),pos(Step),Value) :-
Start < End, Start+Step =< End,
NewStart is Start+Step,
%!, % NEEDED TO MAINTAIN DETERMINACY ON LAST VALUE
between_enum(NewStart,int(End),pos(Step),Value).
现在,为了在枚举结束时完全确定,以下子句需要删减:
between_enum(Start,int(End),pos(Step),Value) :-
Start < End, Start+Step =< End,
NewStart is Start+Step,
!, % <---- HERE
between_enum(NewStart,int(End),pos(Step),Value).
否则:
有剪裁:
?- between(10,15,1,Value).
Value = 10 ;
Value = 11 ;
Value = 12 ;
Value = 13 ;
Value = 14 ;
Value = 15. % This is the end for sure!
没有剪切:
?- between(10,15,1,Value).
Value = 10 ;
Value = 11 ;
Value = 12 ;
Value = 13 ;
Value = 14 ;
Value = 15 ; % Unsure whether this is the end?
false. % Well, turns out it is the end, really!
编译器不应该足够强大来确定在 between_enum(Start,int(End),pos(Step),Value)
之后没有进一步的匹配是可能的 - 这是标记为
int/1
在第二位和pos/1
第三名?
这个 SWI-Prolog 8.1.
编辑
可能是编译器只索引了前两个参数。不需要切入
between_enum(Start,int(End),neg(Step),Value)
后面只有
between_enum(Start,inf,neg(Step),Value)
以及
between_enum(Start,minf,neg(Step),Value)
所以它可以很好地区分 inf
、minf
和 int(_)
。
你对参数顺序的直觉是正确的,可以通过一个简单的实验来证实。
first(tag1(_),_).
first(tag2(_),_).
second(_,tag1(_)).
second(_,tag2(_)).
?- first(tag1(1),2).
true.
?- second(2,tag1(1)).
true ;
false.
这是 Prolog 系统相关的,并且取决于可用的自动索引或可用的索引指令。例如 SWI-Prolog 有自动深度索引,但有一些关于自动多参数索引的特性。所以对于来自 madgen 的例子:
first(tag1(_),_).
first(tag2(_),_).
second(_,tag1(_)).
second(_,tag2(_)).
我进入我的系统,两个查询都不留选择点:
Jekejeke Prolog 4, Runtime Library 1.4.7
?- first(tag1(1),2).
Yes
?- second(2,tag1(1)).
Yes
另一方面,在SWI-Prolog中,第二个查询中留下了一个选择点:
SWI-Prolog (threaded, 64 bits, version 8.3.17)
?- first(tag1(1),2).
true.
?- second(2,tag1(1)).
true ;
false.
这可能会很烦人,而且经常需要使用外观谓词 用于重新排序参数,使它们更适合 SWI-Prolog 特定索引。