List 如何在Prolog中跟踪值?
我是Prolog新手,在OOP中遇到了一些困难。我需要递归地运行一些字符,但记住我所经历的。在OOP中,我只需要创建一个数组或arraylist来跟踪我使用过的任何东西。然而,在Prolog中,我似乎找不到类似的方法来实现这一点。我该如何检查我已经使用了什么 确切的问题是,我想遍历一组字符,如果我两次遇到同一个字符,就停止。我的想法是将每一个都添加到一个列表中,然后检查下一个是否是列表中的成员 谢谢你的帮助List 如何在Prolog中跟踪值?,list,prolog,logical-purity,List,Prolog,Logical Purity,我是Prolog新手,在OOP中遇到了一些困难。我需要递归地运行一些字符,但记住我所经历的。在OOP中,我只需要创建一个数组或arraylist来跟踪我使用过的任何东西。然而,在Prolog中,我似乎找不到类似的方法来实现这一点。我该如何检查我已经使用了什么 确切的问题是,我想遍历一组字符,如果我两次遇到同一个字符,就停止。我的想法是将每一个都添加到一个列表中,然后检查下一个是否是列表中的成员 谢谢你的帮助 谢谢您可能会发现这很有用:从本质上讲,Prolog没有迭代,但它有递归。您需要在列表中循
谢谢您可能会发现这很有用:从本质上讲,Prolog没有迭代,但它有递归。您需要在列表中循环执行您要执行的操作。最基本的实现:
foo([], _). % 1
foo([X|Xs], Seen) :- % 2
\+ memberchk(X, Seen), % 3
foo(Xs, [X|Seen]). % 4
- 当列表为空(1)时,谓词成功
- 如果列表不是空的(2):
- 检查是否已看到列表的第一个元素(3)
- 如果不是(
代表“X失败时成功”),则将元素添加到可见元素列表中,并检查列表的其余部分(4)\+X
- 如果您只想查看列表中是否有重复项,您可以李>
- 考虑对第二个参数使用一个而不是一个列表李>
- 弄清楚你在干什么
- 以下内容基于@Boris的回答;您还可以使用目标
映射列表(dif(X),Seen)
而不是\+memberchk(X,Seen)
来保存:
foo([],。%)1.
foo([X | Xs],见):-%2
地图列表(dif(X),见),%3
foo(Xs[X|Seen])。%4.
我认为问题在于如何找到列表中以第一个重复元素开头的后缀。如果我是对的,那么实现可以遵循以下路线:找到一个重复的元素,并使用一个返回所需后缀或失败的谓词,如果没有重复,则后缀为空。假设第一个参数是没有自由变量的正确闭合列表的实现可以是
stop([],[]).
stop([X|R],Rr) :-
stop_at(R,X,Rr), !.
stop([_|R],Rr) :-
stop(R,Rr).
stop_at([X|R],X,[X|R]) :- !.
stop_at([_|R],X,Rr) :-
stop_at(R,X,Rr).
运行示例:
?- stop([a,b,c],R).
R = [] ? ;
no
?- stop([a,b,c,d,a,e,a,e],R).
R = [a,e,a,e] ? ;
no
?- stop([b,c,d,c,e],R).
R = [c,e] ? ;
no
将找到的每个字符添加到列表中,然后使用此列表检查是否两次获得一个字符,这将与找到的字符列表的大小成线性关系。这可能是,也可能不是可接受的水渍险性能。你有多少不同的角色?仅ASCII可打印字符?完全Unicode?由于只有一些Prolog系统提供数组,因此要获得比列表更好的性能,下一个最佳选择是二叉搜索树,在一般情况下,它将为您提供O(log(n))。但你可以做得更好。当您标记问题时,您可以使用此系统读取黑树库(从YAP继承)。在最坏的情况下,这还应该为您提供O(log(n))。使用此库(作为在其他答案中使用列表的替代方案),您可以按照以下思路编写一些内容:
:- use_module(library(rbtrees)).
foo(List) :-
rb_new(Seen),
foo(List, Seen).
foo([], _).
foo([Head| Tail], Seen) :-
( rb_lookup(Head, _, Seen) ->
true
; rb_insert(Seen, Head, _, Seen2),
foo(Tail, Seen2)
).
与使用列表相比,这是一个值得(性能方面的)替代方案吗?你没有提供足够的细节来回答这个问题。最好运行一些测试。还值得注意的是,在列表中插入是O(1)(当你做
Head
+list
->[Head | list]
)但在红黑树中插入是O(log(n))。我意识到我必须使用递归,但我如何在执行过程中跟踪值?我不明白这个链接有什么帮助。有没有一种方法可以将一个列表初始化为空列表,并在每次递归调用后添加一个字符?@Jon,是的,这正是Prolog中常用的方法。以空列表开始递归,每次递归调用都可以向列表中添加一项。例如,如果您将列表L
作为参数传入,您可以通过引用@Lower将X
添加到头部,我将如何创建空数组?我试图创建一个谓词start([])。但这只是在我每次传递列表时将其重置为空数组。@Jon Prolog没有数组。它有列表。:)您需要携带一个额外的参数:start([],Result)
或类似的内容。由于您在发布的问题描述中没有给出具体的示例,所以我不知道如何更具体。你应该用谷歌搜索“99个序言问题”。他们中的许多人处理列表,并给出答案。然后你会掌握基本列表处理的窍门。是的,我是说列表。我想我还在用其他语言思考。但谢谢你,至少我知道我的方向是正确的。如果你能给出一个问题的具体例子,以及你希望你的程序在这个问题上的表现,这将非常有帮助。否则,您将得到的只是一般性建议。@重复“是”,可能是更好的方法,我在回答中明确表示,我实际上不会编写这样的代码。但是对于这个特殊的问题,我认为引入maplist
和dif
并不能改善答案。实际上,我建议你为后代写一个自己的答案。出于务实的原因,我会推迟选择实现,直到问题得到正确的定义:)但无论如何,这是一个很好的答案(+1)
:- use_module(library(rbtrees)).
foo(List) :-
rb_new(Seen),
foo(List, Seen).
foo([], _).
foo([Head| Tail], Seen) :-
( rb_lookup(Head, _, Seen) ->
true
; rb_insert(Seen, Head, _, Seen2),
foo(Tail, Seen2)
).