混乱的真正根源是一个常见问题与一般的 Prolog 代码。对于 Prolog 谓词的纯度或杂质类型,没有明确的、普遍接受的分类。在手册中,与在标准中类似,纯净和不纯净的内置函数愉快地混合在一起。因此,事情常常会变得混乱,谈论该是、不该是,往往会导致无果而终的讨论。
怎么能说得过去呢?我应该如何解释这个解决方案?
首先,看“模式声明”或“模式指示符”:
min_member(-Min, +列表)
在 SWI 文档中,这描述了程序员如何使用该谓词的方式。因此,第一个参数应该是未实例化的(并且可能在目标内也没有别名),第二个参数应该实例化为某种类型的列表。对于所有其他用途,您必须自行决定。系统假设您能够亲自检查。你真的能做到吗?就我而言,这方面有相当多的困难。国际标准化组织有一个不同的系统这也起源于12月10日.
此外,对于未指定的情况,执行力求“合理”。特别是,它试图在第一个论点上保持坚定。因此,首先独立于 的值计算最小值Min
。然后,将结果值统一为Min
。这种针对滥用的稳健性通常是有代价的。在这种情况下,min_member/2
总是必须访问整个列表。不管这个有没有用。考虑
?- length(L, 1000000), maplist(=(1),L), min_member(2, L).
显然,2 不是最小值L
。这可以通过仅考虑列表的第一个元素来检测。由于定义的通用性,必须访问整个列表。
标准中对这种处理输出统一的方式进行了类似的处理。当(否则)声明性描述(这是第一个内置的) 明确指的是统一,例如
8.5.4 copy_term/2
8.5.4.1 说明
copy_term(Term_1, Term_2)
为真当且仅当Term_2
unifies
有一个术语T
这是重命名的副本 (7.1.6.2)
Term_1
.
or
8.4.3 排序/2
8.4.3.1 描述
sort(List, Sorted)
为真当且仅当Sorted
与
的排序列表List
(7.1.6.5)。
这里是那些只能被理解为输出参数的内置参数(在括号中)。请注意,还有更多实际上是输出参数,但不需要统一过程after一些操作。想想8.5.2arg/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.1findall/3
(3),
8.10.2bagof/3
(3),
8.10.3setof/3
(3).
关于你的直接问题就这么多,背后还有一些更根本的问题:
期限顺序
Historically, "standard" term order1 has been defined to permit the definition of setof/3
and sort/2
about 1982. (Prior to it, as in 1978, it was not mentioned in the DEC10 manual user's guide.)
从 1982 年开始,术语 order 经常(erm、ab-)用于实现其他顺序,特别是因为 DEC10 不直接提供高阶谓词。call/N
两年后(1984 年)发明;但还需要几十年才能被普遍接受。正是因为这个原因,Prolog程序员对排序抱有一种有些漫不经心的态度。他们常常intend对某种术语进行排序,但更喜欢使用sort/2
为此目的——无需任何额外的错误检查。造成这一结果的另一个原因是其出色的性能sort/2
几十年后击败了其他编程语言中的各种“高效”库(我相信 STL 在这方面也有一个错误)。还有代码中的完整魔力 - 我记得一个变量被命名为Omniumgatherum
- 不邀请复制和修改代码。
项顺序有两个问题:变量(可以进一步实例化以使当前顺序无效)和无限项。两者都在当前实现中处理,不会产生错误,但结果仍然未定义。然而,程序员认为一切都会成功。理想情况下,会有比较谓词产生
不清楚情况的实例化错误喜欢这个建议。还有另一个关于不可比较的无限项的错误。
Both SICStus和 SWI 有min_member/2
,但只有 SICStus 有min_member/3
带有一个附加参数来指定所采用的顺序。所以目标
?- min_member(=<, M, Ms).
行为更符合您的期望,但仅限于数字(加上算术表达式)。
脚注:
1 我按照标准术语顺序引用标准,因为这个概念自 1982 年左右就存在,而该标准于 1995 年发布。