是一个无限的清单?

时间:2014-11-17 00:14:37

标签: 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

3 个答案:

答案 0 :(得分:4)

  

在Prolog中,统一X = [1|X]是一种获得无限列表的理智方式吗?

这取决于你是否认为产生无限列表是合理的。在ISO-Prolog中,像X = [1|X]这样的统一需要进行检查(STO),因此未定义。也就是说,符合标准的程序不得执行这样的目标。为避免这种情况发生,有unify_with_occurs_check/2subsumes_term/2。为了保护接口不接收无限期,有acyclic_term/1

所有当前实现都以X = [1|X]终止。 GNU Prolog也终止了:

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

no

但是对于更复杂的情况,需要合理的树统一。将此与Haskell比较 repeat 1 == repeat 1导致ghci冻结。

至于在常规Prolog程序中使用理性树,这在开始时非常有趣,但不能很好地扩展。例如,人们相信在20世纪80年代初期,语法将使用理性树来实现。唉,人们对单独的DCG感到高兴。 这不是离开研究的一个原因是因为Prolog程序员认为存在的许多概念,对于理性树来说并不存在。以词典术语排序为例,它没有理性树的扩展。也就是说,存在无法使用标准术语顺序进行比较的合理树。 (实际上这意味着您获得准随机结果。)这意味着您无法生成包含此类术语的排序列表。这再次意味着像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.

因此,有时候有一些简单的方法来逃避非终止。但往往没有。

答案 1 :(得分:3)

当然,你没有获得无数个,但是所谓的理性循环术语。但是,并非所有Prolog系统都支持循环术语。为理性术语提供一些支持的系统包括CxProlog,ECLiPSe,SICStus,SWI-Prolog和YAP。但请注意,它们之间在使用理性术语执行的计算方面存在差异。

查询如:

X = [1|X], member(Y, X), Y = 1.

需要支持 coinduction 。您可以在Logtalk中轻松实现coinduction,您可以将其与上述所有系统一起使用。 Coinduction要求Prolog系统可以创建合理的术语(使用诸如X = [1|X]之类的查询),这可以统一理性术语,并且可以以非ambigouos方式打印具有理性术语的约束。

有关枚举(或测试)有理列表元素的示例,请参阅:

https://github.com/LogtalkDotOrg/logtalk3/blob/master/examples/coinduction/lists.lgt

此示例的两个示例查询:

?- {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.

如果您对理性术语和共同感兴趣,Logtalk的coinduction示例包括几个单独的示例和参考书目。

答案 2 :(得分:3)

如果要使用无限列表,也可以还原为惰性列表。他们还有共同的阅读。这是Prolog中一个简单的Haskell像take谓词,它将评估懒惰列表[Head | TailClosure]的初始段:

california_housing_dataframe = california_housing_dataframe.reindex(
    np.random.permutation(list(california_housing_dataframe.index)))

这是此框架中的列表的定义:

take(0, _, R) :- !, R = [].
take(N, C, [H|R]) :-
  call(C, [H|T]),
  M is N-1,
  take(M, T, R).

如您所见,您可以扩展共同的定义:

 one([1|one]).

进行这项工作的要求比有理条件下的要求低得多。您只需要在更正2中支持ISO核心标准要求的call/n的Prolog系统。另一方面,不需要理性的术语。

可以通过这种方式定义不合理的列表,也可以对组合了不同流的流处理器进行编码。关于某些应用程序的文献越来越多,例如精确实数和定理证明如Coq,HOL / Isabelle等都可以推断出此类流。

进一步阅读:

Markus Triska-Prolog流
https://www.metalevel.at/various/prost

Dexter Kozen和Alexandra Silva-实用共生
https://www.cs.cornell.edu/~kozen/Papers/Structural.pdf

编辑14.08.2018:
必须说,马库斯·特里斯卡(Markus Triska)的普罗斯特(Prost)和我在这里的帖子都没有通过高阶调用来发明惰性列表。我们在lazy.pl中找到了1983年的Richard O'Keefe片段,其中apply / 2是使用call / n的前体。所以我想这几乎是属于Prolog民俗的。