2011-10-04 60 views
7

我一直被委托在Prolog中实现一个findall版本,而不使用任何Prolog内置函数,除非没有剪切 - 所以基本上在纯Prolog中。Prolog findall执行

我试图寻找所有直系子孙树,并在列表中返回结果

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等任何帮助将非常感激。

谢谢

+0

可能重复的[SWI-Prolog:收集所有解决方案没有findall](http://stackoverflow.com/questions/22492633/swi-prolog-gathering-all-solutions-without-findall) –

+0

你介意结合多线程和递归? –

回答

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]. 
+1

不可读的谓词名称,缺乏评论或解释和讨论...... –

1

看看this solution。 请注意,此解决方案使用名为队列的动态谓词来缓存所有解决方案,直到所有可能耗尽。一旦没有更多的解决方案存在,实现将收回所有事实并编写列表。

这当然是一个简单的解决方案,想象一下如果两个findall同时处于活动状态会发生什么。它也是断言的精确语义有点脆弱和收回,如果特定的序言实施

+0

使用'assertz'这真的不是这样intesting –

2

此外,当您去断言数据,你也可以使用一个额外的逻辑谓词如nb_setarg/3。然后,一旦找到父母,你就会失败回nb_setarg并找到另一个父母。以前找到的所有解决方案都应该保持在你做nb_setarg的期限内,然后在所有结果都用完之后,nb_setarg术语就是答案。 SWI-Prolog的例子很好,但它只是一个计数器。尝试用一个列表(或更好的:差异列表),随着你的进展而建立。

+0

看到我的博客在这里的一些示例代码 - http://onek.posterous.com/my-implementation-of-findall3 – DaveEdelstein

+1

链接中断 –

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,因此使用具有中断的解决方案也是不安全的。最后一个论点也不稳固。这完全留作读者实践这些附加需求和相应替代路径的练习。