下面是一个使用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/1
和no/0
消息。此外,由于我们不使用setup_call_cleanup/3
,因此使用具有中断的解决方案也是不安全的。最后一个论点也不稳固。这完全留作读者实践这些附加需求和相应替代路径的练习。
可能重复的[SWI-Prolog:收集所有解决方案没有findall](http://stackoverflow.com/questions/22492633/swi-prolog-gathering-all-solutions-without-findall) –
你介意结合多线程和递归? –