如果Min是标准术语中最小的成员,则为True.如果List为空,则失败.
?- min_member(3, [1,2,X]).
X = 3.
Run Code Online (Sandbox Code Playgroud)
解释当然是变量在标准的术语顺序中位于所有其他术语之前,并且使用统一.但是,报告的解决方案感觉有些不对劲.
怎么可以说是合理的?我该如何解释这个解决方案?
编辑:
防止min_member/2成功使用此解决方案的一种方法是更改标准库(SWI-Prolog)实现,如下所示:
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)
).
Run Code Online (Sandbox Code Playgroud)
失败而不是抛出实例化错误(@mat在他的回答中建议,如果我理解正确的话)的理由是,这是一个明确的问题:
" [1,2,X]当X是自由变量时,3是最小成员吗?"
对此的答案是(至少对我来说)一个明确的"不",而不是"我无法说出来".
这与以下行为属于同一类sort/2:
?- sort([A,B,C], [3,1,2]).
A = 3,
B = 1,
C = 2.
Run Code Online (Sandbox Code Playgroud)
适用相同的技巧:
?- min_member(3, [1,2,A,B]).
A = 3.
?- var(B), min_member(3, [1,2,A,B]).
B = 3.
Run Code Online (Sandbox Code Playgroud)
混淆的实际来源是普通Prolog代码的常见问题.对于Prolog谓词的纯度或杂质,没有清晰的,普遍接受的分类.在手册中,同样在标准中,纯粹和不纯的内置插件很乐意混合在一起.出于这个原因,事情经常被混淆,并且谈论应该是什么情况,什么不是,往往导致无益的讨论.
怎么可以说是合理的?我该如何解释这个解决方案?
首先,查看"模式声明"或"模式指示器":
min_member(-Min,+ List)
在SWI文档中,这描述了程序员如何使用此谓词的方式.因此,第一个参数应该是未实例化的(并且可能在目标中也没有区分),第二个参数应该实例化为某种列表.对于所有其他用途,您可以自己动手.系统假定您能够自己检查.你真的能这样做吗?就我而言,我对此有很多困难.ISO有一个不同的系统,也起源于DEC10.
此外,对于未指定的情况,实施尝试"合理".特别是,它试图在第一个论点中坚定不移.因此,最小值首先独立于值而计算Min.然后,结果值与统一Min.这种针对滥用的强大功能通常需要付出代价.在这种情况下,min_member/2始终必须访问整个列表.无论这是否有用.考虑
?- length(L, 1000000), maplist(=(1),L), min_member(2, L).
Run Code Online (Sandbox Code Playgroud)
显然,2不是最小值L.这可以通过仅考虑列表的第一个元素来检测.由于定义的一般性,必须访问整个列表.
这种处理输出统一的方式同样在标准中处理.当(否则)声明性描述(内置的第一个)明确引用统一时,您可以发现这些情况,例如
8.5.4 copy_term/2
8.5.4.1描述
copy_term(Term_1, Term_2)如果 与一个重命名的副本(7.1.6.2)的术语Term_2统一
,则为真.T
Term_1
要么
8.4.3 sort/2
8.4.3.1描述
sort(List, Sorted)如果Sorted与(7.1.6.5)
的排序列表统一,则为真List.
以下是内置函数的那些参数(括号中),只能被理解为输出参数.请注意,还有更多有效的输出参数,但在某些操作后不需要统一的过程.考虑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没有直接提供更高阶的谓词.call/N是两年后发明的(1984年); 但需要几十年才能被普遍接受.正是出于这个原因,Prolog程序员对排序有一种漠不关心的态度.他们通常打算对某种类型的术语进行排序,但更喜欢sort/2用于此目的 - 无需任何额外的错误检查.另一个原因是sort/2几十年后在其他编程语言中击败各种"高效"库的出色表现(我相信STL也有这样的错误).代码中的完整魔法 - 我记得一个变量被命名Omniumgatherum- 没有邀请复制和修改代码.
术语顺序有两个问题:变量(可以进一步实例化以使当前排序无效)和无限项.两者都在当前实现中处理而不会产生错误,但结果仍未定义.然而,程序员认为一切都会成功.理想情况下,会有比较谓词产生像这个建议这样的不明原因的实例化错误.无比无限条款的另一个错误.
无论SICStus和SWI有min_member/2,但只有SICStus具有min_member/3与指定使用的顺序一个额外的参数.所以目标
?- min_member(=<, M, Ms).
Run Code Online (Sandbox Code Playgroud)
表现得更符合您的期望,但仅限于数字(加上算术表达式).
脚注:
1我以标准的顺序引用标准,因为这个概念自1982年左右开始存在,而标准是1995年出版的.
显然min_member/2不是一个真正的关系:
?- min_member(X, [X,0]), X = 1.
X = 1.
Run Code Online (Sandbox Code Playgroud)
然而,在简单地通过(非常理想的)联合的交换性交换两个目标之后,我们得到:
?- X = 1, min_member(X, [X,0]).
false.
Run Code Online (Sandbox Code Playgroud)
正如你正确观察到的那样,这显然是非常糟糕的.
约束是解决此类问题的声明性解决方案.在整数的情况下,有限域约束是这种问题的完全声明性解决方案.
在没有约束的情况下,最好在我们知道太少而无法给出正确答案时抛出实例化错误.
这是许多(所有?)谓词的共同属性,这些谓词取决于术语的标准顺序,而两个术语之间的顺序在统一后可能会发生变化。基线是下面的连词,也不能恢复:
?- X @< 2, X = 3.
X = 3.
Run Code Online (Sandbox Code Playgroud)
大多数使用-Value参数注释的谓词表示与pred(Value)相同pred(Var), Value = Var。这是另一个例子:
?- sort([2,X], [3,2]).
X = 3.
Run Code Online (Sandbox Code Playgroud)
如果输入是ground 的话,这些谓词仅表示干净的关系。要求输入是基础的要求太多了,因为只要用户意识到他/她不应该进一步实例化任何有序项,它们就可以有意义地与变量一起使用。从这个意义上说,我不同意@mat。我确实同意,限制肯定可以使其中一些关系变得健全。
| 归档时间: |
|
| 查看次数: |
303 次 |
| 最近记录: |