如果Min是标准术语中最小的成员,则为真。如果List为空,则失败。
?- min_member(3, [1,2,X]).
X = 3.
解释当然是变量在标准的术语顺序中位于所有其他术语之前,并且使用了统一。但是,报告的解决方案在某种程度上是错误的。
怎么可以说是合理的?我该如何解释这个解决方案?
编辑:
阻止min_member/2
成功使用此解决方案的一种方法是更改标准库(SWI-Prolog)implementation,如下所示:
xmin_member(Min, [H|T]) :-
xmin_member_(T, H, Min).
xmin_member_([], Min0, Min) :-
( var(Min0), nonvar(Min)
-> fail
; Min = Min0
).
xmin_member_([H|T], Min0, Min) :-
( H @>= Min0
-> xmin_member_(T, Min0, Min)
; xmin_member_(T, H, Min)
).
失败而不是抛出实例化错误背后的基本原理(@mat在他的回答中建议,如果我理解正确的话)是这是一个明确的问题:
"当X是自由变量时,3是[1,2,X]
的最小成员吗?"
对此的回答(至少对我来说)是一个明确的" No"而不是"我无法说出来。"
这与sort/2
:
?- sort([A,B,C], [3,1,2]).
A = 3,
B = 1,
C = 2.
适用相同的技巧:
?- min_member(3, [1,2,A,B]).
A = 3.
?- var(B), min_member(3, [1,2,A,B]).
B = 3.
答案 0 :(得分:7)
混淆的实际来源是a common problem和普通的Prolog代码。对于Prolog谓词的纯度或杂质,没有清晰的,普遍接受的分类。在手册中,同样在标准中,纯粹和不纯的内置插件很乐意混合在一起。出于这个原因,事情经常被混淆,并且谈论应该是什么情况,什么不是,往往导致无益的讨论。
怎么可以说是合理的?我该如何解释这个解决方案?
首先,查看“模式声明”或“模式指示器”:
min_member(-Min,+ List)
在SWI文档中,这描述了程序员如何使用该谓词的方式。因此,第一个参数应该是未实例化的(并且可能在目标中也没有区分),第二个参数应该被实例化为某种类型的列表。对于所有其他用途,您可以自己动手。系统假定您能够自己检查。你真的能这样做吗?就我而言,我对此有很多困难。 ISO还有different system,originates in DEC10。
此外,对于未指明的案例,实施尝试“合理”。特别是,它试图在第一个论点中坚定不移。因此,首先计算最小值,而不考虑Min
的值。然后,结果值与Min
统一。这种针对滥用的强大功能通常需要付出代价。在这种情况下,min_member/2
始终必须访问整个列表。无论这是否有用。考虑
?- length(L, 1000000), maplist(=(1),L), min_member(2, L).
显然,2不是L
的最小值。这可以通过仅考虑列表的第一个元素来检测。由于定义的一般性,必须访问整个列表。
这种处理输出统一的方式同样在标准中处理。当(否则)声明性描述(which is the first of a built-in)明确引用统一时,您可以发现这些情况,例如
8.5.4 copy_term / 2
8.5.4.1说明
如果copy_term(Term_1, Term_2)
统一了,则
Term_2
为真 术语T
是一个重命名的副本(7.1.6.2)Term_1
。
或
8.4.3 sort / 2
8.4.3.1说明
如果sort(List, Sorted)
与
结合,则
Sorted
为真 排序的List
(7.1.6.5)列表。
以下是内置函数的那些参数(括号中),只能被理解为输出参数。请注意,还有更多有效的输出参数,但在某些操作之后不需要统一的过程。考虑8.5.2 arg/3
(3)或8.2.1 (=)/2
(2)或(1)。
8.5.4 1 copy_term/2
(2),
8.4.2 compare/3
(1),
8.4.3 sort/2
(2),
8.4.4 keysort/2
(2),
8.10.1 findall/3
(3),
8.10.2 bagof/3
(3),
8.10.3 setof/3
(3)。
对于你的直接问题,还有一些更基本的问题:
历史上,“标准”术语顺序 1 已被定义为允许setof/3
和sort/2
约定于1982年。(在此之前,如1978年,它在DEC10 手册用户指南中未提及。)
从1982年开始,用于实现其他订单的定期订单经常(erm,ab-),特别是因为DEC10没有直接提供更高阶的谓词。两年后(1984年)发明了call/N
;但需要几十年才能被普遍接受。正是出于这个原因,Prolog程序员对排序有一种漠不关心的态度。通常他们打算对某种类型的术语进行排序,但更喜欢使用sort/2
来实现此目的 - 无需任何其他错误检查。另一个原因是几十年后sort/2
在其他编程语言中击败各种“高效”库的出色表现(我相信STL也有这样的错误)。代码中的完整魔法 - 我记得一个变量名为Omniumgatherum
- 没有邀请复制和修改代码。
术语顺序有两个问题:变量(可以进一步实例化以使当前排序无效)和无限期。两者都在当前实现中处理而不会产生错误,但结果仍未定义。然而,程序员认为一切都会成功。理想情况下,会产生比较谓词 不明原因like this suggestion的实例化错误。无可比拟的无限期的另一个错误。
SICStus和SWI都有min_member/2
,但只有SICStus有min_member/3
并附加参数来指定所使用的顺序。所以目标
?- min_member(=<, M, Ms).
表现得更符合您的期望,但仅限于数字(加上算术表达式)。
脚注:
1我引用标准,按标准术语顺序,这个概念自1982年左右开始存在,而标准是1995年出版的。
答案 1 :(得分:5)
显然min_member/2
不是真正的关系:
?- min_member(X, [X,0]), X = 1.
X = 1.
然而,在简单地通过(非常理想的)联合的交换性交换两个目标之后,我们得到:
?- X = 1, min_member(X, [X,0]).
false.
正如你正确观察到的那样,这显然非常糟糕。
约束是针对此类问题的声明性解决方案。在整数的情况下,有限域约束是这类问题的完全声明性解决方案。
如果没有约束,最好在我们知道太少而无法给出正确答案时抛出实例化错误。
答案 2 :(得分:4)
这是许多(所有?)谓词的共同属性,它依赖于术语的标准顺序,而统一后两个术语之间的顺序可能会发生变化。基线是下面的连接,无法恢复:
?- X @< 2, X = 3.
X = 3.
对于参数使用-Value
注释的大多数谓词都说pred(Value)
是相同的
为pred(Var), Value = Var
。这是另一个例子:
?- sort([2,X], [3,2]).
X = 3.
如果输入 ground ,这些谓词仅表示干净的关系。要求输入接地是太多了,因为它们可以有意义地与变量一起使用,只要用户知道他/她不应该进一步实例化任何有序的术语。从这个意义上说,我不同意@mat。我同意约束肯定会使这些关系中的某些关系健全。
答案 3 :(得分:2)
我希望我的第三个答案不会偏离主题。我没有编辑前两个中的一个,因为我认为这是一个完全不同的想法。我想知道这种不良行为是否存在:
?- min_member(X, [A, B]), A = 3, B = 2.
X = A, A = 3,
B = 2.
如果在A
和B
实例化的情况下可以推迟某些条件,则可以避免。
promise_relation(Rel_2, X, Y):-
call(Rel_2, X, Y),
when(ground(X), call(Rel_2, X, Y)),
when(ground(Y), call(Rel_2, X, Y)).
min_member_1(Min, Lst):-
member(Min, Lst),
maplist(promise_relation(@=<, Min), Lst).
我希望min_member_1(?Min, ?Lst)
能够表达一种关系,即Min
始终低于Lst
中的任何元素(标准顺序)。
?- min_member_1(X, L), L = [_,2,3,4], X = 1.
X = 1,
L = [1, 2, 3, 4] .
如果变量稍后被实例化,它们被绑定的顺序变得很重要,因为可以在自由变量和实例变量之间进行比较。
?- min_member_1(X, [A,B,C]), B is 3, C is 4, A is 1.
X = A, A = 1,
B = 3,
C = 4 ;
false.
?- min_member_1(X, [A,B,C]), A is 1, B is 3, C is 4.
false.
但是,可以通过将所有这些目标统一在同一目标中来避免这种情况:
?- min_member_1(X, [A,B,C]), [A, B, C] = [1, 3, 4].
X = A, A = 1,
B = 3,
C = 4 ;
false.
<强>版本强>
如果比较仅用于实例化变量,则可以更改promise_relation/3
以仅在两个变量实例化时检查关系:
promise_relation(Rel_2, X, Y):-
when((ground(X), ground(Y)), call(Rel_2, X, Y)).
一个简单的测试:
?- L = [_, _, _, _], min_member_1(X, L), L = [3,4,1,2].
L = [3, 4, 1, 2],
X = 1 ;
false.
!由于错误的评论和建议,我们修改了首发帖子。
答案 4 :(得分:1)
这就是min_member/2
的实施方式:
min_member(Min, [H|T]) :-
min_member_(T, H, Min).
min_member_([], Min, Min).
min_member_([H|T], Min0, Min) :-
( H @>= Min0
-> min_member_(T, Min0, Min)
; min_member_(T, H, Min)
).
所以似乎min_member/2
实际上尝试统一 Min
(第一个参数),其中List
中的最小元素是标准的术语顺序。
答案 5 :(得分:0)
我对您的xmin_member
实施情况有所了解。它在此查询中失败:
?- xmin_member(1, [X, 2, 3]).
false.
当列表可能包含自由变量时,我尝试包含这种情况。所以,我想出了这个:
ymin_member(Min, Lst):-
member(Min, Lst),
maplist(@=<(Min), Lst).
当然,在效率方面更糟糕,但它适用于这种情况:
?- ymin_member(1, [X, 2, 3]).
X = 1 ;
false.
?- ymin_member(X, [X, 2, 3]).
true ;
X = 2 ;
false.