List 一个无限的清单是理智的吗?

List 一个无限的清单是理智的吗?,list,prolog,cyclic,iso-prolog,coinduction,List,Prolog,Cyclic,Iso Prolog,Coinduction,在Prolog中,统一X=[1 | X]是获得无限多个一组的合理方法吗?SWI Prolog没有任何问题,但GNU Prolog只是挂起 我知道在大多数情况下,我可以用 one(1). one(X) :- one(X). 但我的问题是,如果一个人可以在一个“正常”的Prolog实现中使用表达式X=[1 | X],member(Y,X),Y=1。当然,你不会得到无穷多的一,但这就是所谓的有理的或循环的术语。然而,并非所有的Prolog系统都支持循环项。为rational术语提供一些支持的系统包括

在Prolog中,统一
X=[1 | X]
是获得无限多个一组的合理方法吗?SWI Prolog没有任何问题,但GNU Prolog只是挂起

我知道在大多数情况下,我可以用

one(1).
one(X) :- one(X).

但我的问题是,如果一个人可以在一个“正常”的Prolog实现中使用表达式
X=[1 | X],member(Y,X),Y=1

当然,你不会得到无穷多的一,但这就是所谓的有理的循环的术语。然而,并非所有的Prolog系统都支持循环项。为rational术语提供一些支持的系统包括CxProlog、ECLiPSe、SICStus、SWI Prolog和YAP。但是请注意,它们之间在使用有理项可以执行的计算方面存在差异

查询,例如:

X = [1|X], member(Y, X), Y = 1.
需要对共导入的支持。您在Logtalk中有一个可移植的coinduction实现,可以与上面提到的所有系统一起使用。共导入要求Prolog系统能够创建rational术语(使用诸如
X=[1 | X]
)这样的查询,该查询能够统一rational术语,并且能够以无歧义的方式打印带有rational术语的绑定

有关枚举(或测试)rational list元素的示例,请参阅:

此示例的两个示例查询:

?- {coinduction(loader)}.
...
% (0 warnings)
true.
?- X = [1|X], lists::comember(Y, X), Y = 1.
X = [1|X],
Y = 1 ;
false.

?- X = [1, 2, 3| X], lists::comember(Y, X).
X = [1, 2, 3|X],
Y = 1 ;
X = [1, 2, 3|X],
Y = 2 ;
X = [1, 2, 3|X],
Y = 3 ;
false.
如果您对rational术语和共归纳感兴趣,Logtalk的示例包括几个单独的示例和参考书目

在Prolog中,统一
X=[1 | X]
是获得无限多个一组的合理方法吗

这取决于你是否认为生产无限列表是明智的。在ISO Prolog中,像
X=[1 | X]
这样的统一要经过发生检查(STO),因此是未定义的。也就是说,一个符合标准的程序不能执行这样的目标。为了避免这种情况发生,有
unified\u with\u ocurses\u check/2
subsumes\u term/2
。为了防止接口接收无限项,有
非循环项/1

所有当前的实现都会因
X=[1 | X]
而终止。此外,GNU Prolog终止:

| ?- X = [1|X], acyclic_term(X).

no
但对于更复杂的情况,需要使用rational树统一。将此与Haskell进行比较
repeat 1==repeat 1
导致
ghci
冻结

至于在常规Prolog程序中使用rational树,这在一开始是非常有趣的,但扩展得不太好。例如,在20世纪80年代初的一段时间里,人们相信语法将使用rational树来实现。唉,光有DCG,人们就够高兴的了。 这并没有离开研究的一个原因是,因为Prolog程序员假设存在的许多概念对于rational树来说并不存在。以字典术语排序为例,它对有理树没有扩展。也就是说,有些有理树不能用标准术语顺序进行比较。(实际上,这意味着您将获得准随机结果。)这意味着您无法生成包含此类术语的排序列表。这再次意味着许多内置的,如
bagof/3
不再可靠地使用无限项

对于您的示例查询,请考虑以下定义:

memberd(X, [X|_Xs]).
memberd(E, [X|Xs]) :-
   dif(E,X),
   memberd(E, Xs).

?- X = 1, Xs=[1|Xs], memberd(X,Xs).
X = 1,
Xs = [1|Xs] ;
false.
 Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.1)
 SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

 ?- take(5,one,L).
 L = [1, 1, 1, 1, 1]. 

因此,有时有一些简单的方法可以避免不终止。但是通常没有。如果你想使用无限列表,你也可以选择恢复到惰性列表。他们也有一个共同的阅读。在Prolog中有一个简单的类似Haskell的take谓词,它将计算惰性列表的初始段[Head | TailClosure]:

take(0, _, R) :- !, R = [].
take(N, C, [H|R]) :-
  call(C, [H|T]),
  M is N-1,
  take(M, T, R).
以下是该框架中的定义列表:

 one([1|one]).
如您所见,您可以展开共导定义:

memberd(X, [X|_Xs]).
memberd(E, [X|Xs]) :-
   dif(E,X),
   memberd(E, Xs).

?- X = 1, Xs=[1|Xs], memberd(X,Xs).
X = 1,
Xs = [1|Xs] ;
false.
 Welcome to SWI-Prolog (threaded, 64 bits, version 7.7.1)
 SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.

 ?- take(5,one,L).
 L = [1, 1, 1, 1, 1]. 
这项工作的要求比理性条款的要求要低得多。您只需要支持ISO核心标准勘误表2中要求的Prolog系统。另一方面,不需要合理的条款

可以用这种方式定义非理性列表,也可以使用组合不同流的代码流处理器。关于某些应用的文献越来越多,例如精确实数和定理证明者,如Coq,HOL/Isabelle。。我们可以对这些溪流进行推理

进一步阅读:

Markus Triska-序言流

德克斯特·科岑和亚历山德拉·席尔瓦-实用的共同产品

编辑2018年8月14日:

必须指出的是,无论是来自马库斯·特里斯卡的普罗斯特,还是我在这里的帖子,都没有通过高阶调用发明懒惰列表。我们在这里找到1983年的Richard O'Keefe片段,其中使用了call/n的前身apply/2。所以我猜它几乎属于序言中的民间传说。

。。。即使没有
call/n
,也可以通过为所有惰性列表定义谓词(即,具有“额外的间接级别”)编写。。[…],G.,对吗?所以这只是句法上的差异。使用特殊的名称(实际上是构建一种解释器)正是我当时想到的。也许当时我还不知道打电话的事,或者我觉得很舒服。:)冻结/2,因为这里当然也是一个选项。但是它在垃圾收集方面有很多问题。至少在我的系统里。但是当系统具有良好的最后一次调用优化时,上面的调用/n解决方案不会留下很多额外的垃圾。嗯,我只是在考虑
冻结
:)--很高兴知道,关于GC。看,这似乎是一个输入错误(参数被交换):它不应该是
seq_-take(seq,N,Ts):-短语(seq_-take_(N,seq),Ts)。
?另外,看起来
seq_take_
犯了一个典型的错误,强制流中的元素过多:
seq_take(seq,1,Ts)
根本不应该调用
seq_next/2
最后,素数是