该谓词if_/3似乎在Stack Overflow的Prolog部分的少数主要贡献者中相当受欢迎.
这个谓词是这样实现的,由@false提供:
if_(If_1, Then_0, Else_0) :-
call(If_1, T),
( T == true -> call(Then_0)
; T == false -> call(Else_0)
; nonvar(T) -> throw(error(type_error(boolean,T),_))
; /* var(T) */ throw(error(instantiation_error,_))
).
Run Code Online (Sandbox Code Playgroud)
但是,我一直无法找到这个谓词的作用的清晰,简单和简洁的解释,以及它与Prolog的经典if-then-else结构相比有什么用处if -> then ; else.
我发现的大多数链接直接使用这个谓词,并且提供了很少的解释,为什么它被使用,Prolog中的非专家可以轻松理解.
I #> 0, I #< 10, indomain(I).
Run Code Online (Sandbox Code Playgroud)
以前的代码显然执行以下操作:
I = 1 ;
I = 2 ;
I = 3 ;
I = 4 ;
I = 5 ;
I = 6 ;
I = 7 ;
I = 8 ;
I = 9.
Run Code Online (Sandbox Code Playgroud)
以下代码不起作用(参数未充分实例化):
I #> 0, indomain(I).
Run Code Online (Sandbox Code Playgroud)
现在我明白在这种情况下存在无限数量的可能绑定I,并且CLPFD适用于有限域,顾名思义.
但是我不明白为什么在这种特殊情况下存在这种限制.是不是可以列举从最小到最大规范的可能解决方案,并获得以下内容:
I = 1 ;
I = 2 ;
I = 3 ;
.
.
.
Run Code Online (Sandbox Code Playgroud)
即使存在多个变量的问题,也可以说:
0 #< I, I #< J, label([I,J]).
Run Code Online (Sandbox Code Playgroud)
为什么不可能实现它,以便发生以下行为:
I = 1,
J …Run Code Online (Sandbox Code Playgroud) ?- permutation([A,B,C],Z).
Z = [A, B, C] ;
Z = [A, C, B] ;
Z = [B, A, C] ;
Z = [B, C, A] ;
Z = [C, A, B] ;
Z = [C, B, A] ;
false.
Run Code Online (Sandbox Code Playgroud)
说得通.我可以处理排列,[A,B,C]并且排列包含与in相同的元素[A,B,C],因此我对这些元素所做的一切都将应用于我的原始列表.
现在:
?- findall(X, permutation([A,B,C], X), Z).
Z = [[_G1577, _G1580, _G1583], [_G1565, _G1568, _G1571], [_G1553, _G1556, _G1559], [_G1541, _G1544, _G1547], [_G1529, _G1532, _G1535], [_G1517, _G1520, _G1523]].
Run Code Online (Sandbox Code Playgroud)
为什么??为什么findall/3给我列出包含完全不相关的变量的列表,而不是A,B,C?这些列表Z甚至没有相互关联,所以我得到的结果实际上只有6个长度为3的随机列表,这完全不是我所查询的.
有了这种行为,我们得到如下荒谬的结果:
?- findall(X, …Run Code Online (Sandbox Code Playgroud) 假设我正在研究这个玩具示例(问题的重点显然不是解决这个示例):
p([]).
p([H|T]) :- H = 0, call_predicate(p,T).
call_predicate(Name,Arg) :- call(Name,Arg).
Run Code Online (Sandbox Code Playgroud)
到目前为止,一切都很好。现在假设我想添加一个call_predicate/1不需要谓词名称的谓词:
call_predicate(Arg) :- Name = ??, call(Name,Arg).
Run Code Online (Sandbox Code Playgroud)
这样我就可以使用 in p: call_predicate(T),隐式地知道我想调用同名的谓词。
那么问题是,在知道这是调用的谓词的名称的情况下,如何p从 中检索名称?call_predicate/1call_predicate/1
一个类似的问题是,如果它比第一个更容易,我如何检索执行中一次所处的当前谓词的名称?
我有时态数据,其中一些时间间隔仅包含缺失值.我想明确地显示那些缺失的值间隔.
现在,我的解决方案是检查值是否是NaN这样的:
plot file_name using 1:(stringcolumn(num_column) eq "NaN" ? 1/0 : column(num_column)) with lines,\
"" using 1:(stringcolumn(num_column) eq "NaN" ? 1000 : 1/0) with points
Run Code Online (Sandbox Code Playgroud)
这将导致绘制点y = 1000而不是缺失值的行,这会得到以下结果:
然而,这并不理想,因为a)我需要指定y绘制点的值,b)它非常难看,特别是当数据集的时间较长时.
我想生产这样的东西:
也就是说,用一种颜色完全填充这个间隔(可能与我的图像不同,有一些透明度).请注意,在这些示例中,只有一个缺失值的间隔,实际上在一个图上可以有任意数量的缺失值.
假设我想表示这样的整数: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).
Run Code Online (Sandbox Code Playgroud)
这按预期工作.然而,它具有接受诸如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 …Run Code Online (Sandbox Code Playgroud) 这是第一个观察:
?- is_list([]), is_list([_,_,_]).
true.
Run Code Online (Sandbox Code Playgroud)
这是另一个观察:
?- [] = _, [_,_,_] = _.
true.
Run Code Online (Sandbox Code Playgroud)
因此,为什么会is_list/1这样实施
?- is_list(_).
false.
Run Code Online (Sandbox Code Playgroud)
要么
?- is_list([_|_]).
false.
Run Code Online (Sandbox Code Playgroud)
何时_可以清楚地统一列表?这不是逻辑上更健全的true吗?
在SWI-Prolog的文档中is_list/1,注释说:
在5.0.1之前的版本中,
is_list/1只检查[]或[_|_]与proper_list/1有电流的作用is_list/1.目前的定义符合事实上的标准.
为什么这是事实上的标准?
在SWI-Prolog中,以下查询给出了以下结果:
?- X mod 2 #= 0, X mod 2 #= 0.
X mod 2#=0,
X mod 2#=0.
Run Code Online (Sandbox Code Playgroud)
虽然正确,但显然不需要第二个约束
同理:
?- dif(X,0), dif(X,0).
dif(X, 0),
dif(X, 0).
Run Code Online (Sandbox Code Playgroud)
有没有办法避免这种重复约束?(显然,最正确的方法是不编写导致这种情况的代码,但并不总是那么容易).
在 Prolog 中,集合似乎是使用列表来表示的。
例如,以下是union/3SWI-Prolog 的实现:
union([], L, L) :- !.
union([H|T], L, R) :-
memberchk(H, L), !,
union(T, L, R).
union([H|T], L, [H|R]) :-
union(T, L, R).
Run Code Online (Sandbox Code Playgroud)
然而这个谓词不是很有声明性,例如:
?- union([1,2,3],X,[1,2,3,4]).
X = [1, 2, 3, 4].
Run Code Online (Sandbox Code Playgroud)
这应该留下一些选择点,或者:
?- union(X,[1,2],[1,2,3,4]).
<infinite loop>
Run Code Online (Sandbox Code Playgroud)
这甚至不起作用!
除此之外,我们还发现以下问题:
?- union([1,2,3],[4,5],[1,2,3,5,4]).
false.
?- union([1,1,1],[4,5],[1,1,1,4,5]).
true.
Run Code Online (Sandbox Code Playgroud)
如果我们真的谈论集合,这显然是错误的。
我们可以清楚地看到,使用列表来讨论集合并不简单,因为:
因此,我们要么发现作用于集合的谓词可以削减可能的解决方案(例如,联合的实现仅在集合有序的情况下才起作用),要么找到根据变量的实例化提供无用选择点的谓词(例如,联合谓词将具有作为许多选择点作为结果集的排列数)。
在 Prolog 中应该如何正确实现适用于集合的谓词?
这个问题非常笼统,并不特定于此处使用的示例union/3。
假设我有一个谓词foo/2,它定义了它的第一个和第二个参数之间的关系.
改变这种实现的最惯用和最有效的方法是什么foo/2:
如果它的两个参数都是基础的,它就像以前一样(如果关系成立则成功,否则失败).
如果两个参数中的一个(或两个)都是空闲的,它会"约束"这两个参数,这样当它们接地时,将检查关系.
换句话说,如何正确地实现由dif/2任何类型的用户定义关系表现出来的行为?
listing(dif/2). 没什么帮助.
prolog ×9
clpfd ×3
list ×2
unification ×2
gnuplot ×1
if-statement ×1
prolog-dif ×1
reflection ×1
set ×1
swi-prolog ×1