我试图理解在Prolog中使用union(内置谓词)。在许多情况下,它应该成功时似乎失败了。它似乎与列表元素的顺序有关。所有下面的案例都失败了(他们回来了"假。")。
?- union([1,2,3],[],[2,3,1]).
?- union([1,5,3], [1,2], [1,5,3,2]).
?- union([4,6,2,1], [2], [1,2,4,6]).
?- union([1,2], [], [2,1]).
所有这些都不是真的吗?关于为什么这些案例会失败的任何解释都会非常有帮助。
另外:为什么下面没有成功并找到A的正确列表?
?- union([1,5,3], A, [4,1,5,3,2]). /** comes back with "fail." */
答案 0 :(得分:4)
这里有几个问题。声明性和程序性的。让我们从声明的开始,他们真的坐得更深。使用适当的编程技术可以轻松处理程序方面,如in this answer。
当我们考虑谓词的声明性属性时,我们会考虑它的解决方案集。所以我们假装我们关心的是谓词将描述的解决方案。我们将完全忽略所有这些都是如何实现的。对于非常简单的谓词,这是一个简单的事实枚举 - 就像数据库表一样。在这种情况下,这一切都很明显。如果解决方案集是无限的,那就变得更加不直观了。这很容易发生。想想查询
?- length(Xs,1).
这个无害的查询请求所有长度为1的列表。他们都是!让我数数 - 这无限多!
在我们看看Prolog产生的实际答案之前,请考虑在这种情况下你会做些什么。你会如何回答这个问题?我的一些微弱尝试
?- length(Xs, 1).
Xs = [1]
; Xs = [42]
; Xs = [ben+jerry]
; Xs = [feel([b,u,r,n])]
; Xs = [cromu-lence]
; Xs = [[[]]]
; ... % I am running out of imagination
Prolog应该生成所有那些无限多的值吗?这需要多长时间?你需要多少时间盯着文字墙?你的一生显然是不够的。
有一条出路:逻辑变量!
?- length(Xs, 1).
Xs = [_A].
% ^^
这个小_A
允许我们将所有奇怪的解决方案折叠成单一答案!
所以在这里我们真的有很多运气:我们用这个不错的变量来驯服无限。
现在回到你的关系。在那里,我们想要将集合表示为列表。列表显然不是本身的集合。考虑列表[a,a]
和列表[a]
。虽然它们不同,但它们代表的是同一套。想一想:[a]
有多少个替代表示?是的,无限多。但是现在,逻辑变量无法帮助我们紧凑地表示所有这些 1 。因此,我们必须逐个列举它们。但是,如果我们必须列举所有这些答案,实际上所有查询都不会因为无限多个明确枚举的解决方案而终止。好吧,有些人仍然会:
?- union([], [], Xs).
Xs = [].
所有地面查询。所有失败的查询。但是,一旦我们有一个像
这样的变量?- union([a], [], Xs).
Xs = [a]
; Xs = [a,a]
; Xs = [a,a,a]
; ...
我们已经深入到非终止。
因此,我们必须做出一些决定。我们不知何故需要驯服无限。一个想法是考虑实际关系的一个子集,它以某种方式倾向于一方。如果我们想提问union([1,2],[3,4], A3)
这样的问题,那么强制使用我们拥有此functional dependency
A1,A2→A3
有了这个函数依赖关系,我们现在为每对A3
,A1
确定A2
的一个值。以下是一些例子:
?- union([1,5,3], [1,2], A3).
A3 = [5,3,1,2].
?- union([1,2,3], [], A3).
A3 = [1,2,3].
请注意,Prolog始终将.
作为结尾。这意味着Prolog说:
迪西!我已经说过。没有更多的解决方案。
(其他Prologs会呻吟" No"最后。)因此,查询(来自您的评论)现在失败了:
?- union([1,5,3], [1,2], [1,5,3,2]).
false.
?- union([1,2,3],[],[2,3,1]).
false.
如此强制,功能依赖现在大大限制了解决方案集。而这种限制是实施者的任意决定。可能会有所不同!有时,重复删除,有时不删除。如果A1
和A2
都是重复的免费列表,则结果A3
也将免费重复。
在查看其实现后,以下内容似乎成立(您不需要这样做,文档应该足够好 - 它不是没有):最后一个参数中的元素结构如下,按顺序:
A1的元素也不会出现在A2中。按A1的相对顺序。
A2的所有元素按原始顺序排列。
所以有了这个功能依赖性,其他属性已被潜入。例如A2总是A3的后缀!因此,以下情况不可能成立,因为没有A3的后缀可以使此查询成立:
?- union([1,5,3], A2, [4,1,5,3,2]).
false.
还有更多的违规行为可以在声明级别上描述。通常,为了提高效率,关系过于笼统。像:
?- union([],non_list,non_list).
这些问题经常被忽略,因为我们注意到我们只对那些列表(如[a,b]
)或部分列表(如[a,b|Xs]
)参数的目标感兴趣。
反正。我们现在终于描述了我们期望的所有声明属性。现在是下一部分:应该充分实施这种关系!还有一大堆问题在等着我们!
使用SWI的library(lists)
,我得到:
?- union([1,2], [X], [1,2,3]).
false.
?- X = 3, union([1,2], [X], [1,2,3]).
X = 3.
哪个是不正确的:这只能在程序上理解,看实际的实现。这不再是一个干净的关系。但是这个问题can be fixed!
通过坚持Prolog的纯粹单调子集,您可以完全避免正确性问题。请参阅上文了解更多信息。
1)说实话,有可能用某种形式的约束来表示无限集。但是现有的Prolog系统提供的集合没有单一的库这一事实应该清楚地表明这不是一个明显的选择。