Prolog findall实施

时间:2011-10-04 12:17:22

标签: multithreading list recursion prolog prolog-findall

我的任务是在Prolog中实现一个版本的findall,而不使用任何Prolog内置函数,除了not和cut之外 - 所以基本上是纯粹的Prolog。

我正在尝试在树中搜索所有直接后代,并将结果返回到列表中

parent(a, b).
parent(b, c).
parent(b, d).
parent(e, d).

到目前为止我所拥有的是:

find(X, L) :- find2(X, [], L).
find2(X, Acc, L) :- parent(Y, X), find2(Y, [Y|Acc], L).
find2(_, Acc, Acc).

例如,当我进入时,我想得到什么:

find(a,X).

将是:

X = [b, c, d]

(订单不重要)

然而我得到了:

X = [b, c] ;
X = [b, d] ;
X = [b] ;
X = [].

我是Prolog的新手,所以对此的任何帮助都会非常感激。

由于

4 个答案:

答案 0 :(得分:2)

除了随意断言数据外,您还可以使用额外逻辑谓词,例如nb_setarg/3。然后,一旦找到父级,您就会失败回到nb_setarg并找到另一个父级。以前找到的所有解决方案都应该保留在你执行nb_setarg的术语中,然后在所有结果都用尽之后,nb_setarg术语就是答案。 SWI-Prolog的例子很好,但它只是一个反击。尝试使用列表(或者更好的:差异列表)来构建它。

答案 1 :(得分:1)

看看this solution。 请注意,此解决方案使用名为queue的动态谓词来缓存所有解决方案,直到所有可能性都用完为止。一旦不再存在解决方案,实现将撤回所有事实并组成列表。

这当然是一个简化的解决方案,想象如果两个findall同时处于活动状态会发生什么。如果特定的prolog实现

,它在assert和retract的确切语义上也有点脆弱

答案 2 :(得分:1)

谢谢你帮助大家。我设法通过添加一个谓词来解决它,该谓词根据当前列表检查每个项目,如果它已经存在则失败:

find(X, Loa) :- find(X, [], Loa), !.
find(X, Acc, Loa) :- dec(Y, X), uList(Y, Acc, AccNew), find(X, AccNew, Loa).
find(_, Acc, Acc).

dec(X,Y) :- parent(X,Y).
dec(X,Y) :- parent(X,Z), dec(Z,Y).

uList(X, [], [X])  :- !.
uList(H, [H|_], _) :- !, fail.
uList(X, [H|T], L) :- uList(X, T, Rtn), L = [H|Rtn].

答案 3 :(得分:0)

这是一个使用SWI-Prolog队列和线程的解决方案。它使用旧的现有API并在Tarau's Engines上执行某些操作。我假设线程创建将复制模板和目标。然后我假设队列发送将再次执行每个解决方案的副本。

因此,与经典的findall相比,您将在一个模板和目标副本上获得盈余,但除此之外,它还会将每个解决方案复制为经典的findall。关于要点here的来源。但是通过修改收集的threadall2,人们也可以实现各种聚合:

% threadall(+Term, +Goal, -List)
threadall(T, G, L) :-
   message_queue_create(J, [max_size(1)]),
   thread_create(threadall3(T, G, J), _, [detached(true)]),
   thread_get_message(J, A),
   threadall2(J, A, L),
   message_queue_destroy(J).

% threadall3(+Term, +Goal, +Queue)
threadall3(T, G, J) :-
   G, thread_send_message(J, the(T)), fail.
threadall3(_, _, J) :-
   thread_send_message(J, no).

% threadall2(+Queue, +Term, -List)
threadall2(J, the(T), [T|L]) :- !,
   thread_get_message(J, A),
   threadall2(J, A, L).
threadall2(_, no, []).

这是一个示例运行。我希望我能正确记账。该线程是使用detach(true)创建的,因此当线程终止时我们不需要一些句柄。消息队列被明确销毁。以下是SWI-Prolog中的一些示例运行,我们看到它按预期工作:

Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.23)
Copyright (c) 1990-2015 University of Amsterdam, VU Amsterdam

?- threadall(X, between(0, 5, X), L).
L = [0, 1, 2, 3, 4, 5].

?- threadall(X-Y, (between(0, 2, X), 
                   threadall(Z, between(0, 2, Z), Y)), L).
L = [0-[0, 1, 2], 1-[0, 1, 2], 2-[0, 1, 2]].

我们的代码只实现了通常的快乐路径:我们只实现the/1no/0消息。此外,由于我们不使用setup_call_cleanup/3,因此使用具有中断的解决方案也是不安全的。最后一个论点也不坚定。这完全留给读者练习这些附加要求和相应的备用路径。