在Prolog中,统一X = [1|X]
是一种理智的方式来获得无限的列表吗? SWI-Prolog没有任何问题,但GNU Prolog只是挂起。
我知道在大多数情况下我可以用
替换列表one(1).
one(X) :- one(X).
但我的问题是明确的,如果可以在“理智的”Prolog实现中使用表达式X = [1|X], member(Y, X), Y = 1
。
答案 0 :(得分:4)
在Prolog中,统一
X = [1|X]
是一种获得无限列表的理智方式吗?
这取决于你是否认为产生无限列表是合理的。在ISO-Prolog中,像X = [1|X]
这样的统一需要进行检查(STO),因此未定义。也就是说,符合标准的程序不得执行这样的目标。为避免这种情况发生,有unify_with_occurs_check/2
,subsumes_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民俗的。