序言的findall实施序言的findall实施(Prolog findall Implementa

2019-05-12 11:11发布

我一直在负责实施在Prolog的一个版本的findall,而无需使用任何Prolog的内置插件,除了不与切 - 纯的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等任何帮助将非常感激。

谢谢

Answer 1:

此外,当您去断言数据,你也可以使用一个额外的逻辑谓词如nb_setarg / 3 。 然后,一旦家长发现,你不能回到过去nb_setarg,找到另一位家长。 以前发现的解决方案应该留在你做nb_setarg上来看,那么所有的结果都用尽之后,nb_setarg项是答案。 该SWI-Prolog的例子是好的,但它只是一个计数器。 试图用List(或更好的:差异列表)做这件事是基础,因为你去。



Answer 2:

看看这个解决方案 。 请注意,此解决方案使用动态指定的队列谓词以缓存所有的解决方案,直到所有的可能性都用尽。 一旦没有更多的解决方案存在,执行收回所有的事实和组成名单。

当然,这是一个有点简化的解决方案,设想如果两个的findall将在同一时间被激活,会发生什么。 它也是断言的精确语义有点脆弱,如果特定的序言执行收回



Answer 3:

感谢您的帮助大家。 我设法通过加入核对当前列表中的每个项目谓词来解答它到底和失败,如果它已经存在:

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


Answer 4:

下面是一个使用SWI-Prolog的队列和线程的解决方案。 它使用旧的现有的API和做的东西沿着Tarau的发动机 。 我认为线程的创建将复制的模板和目标。 然后,我认为队列发送将再次做每个解决方案的副本。

因此,相比于传统的findAll你将有一个模板和目标副本盈余,但除此之外,它还会复制每个溶液,作为经典的findall。 来源要点这里 。 但是,改装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, []).

下面是一个例子运行。 我希望我做了正确的簿记。 螺纹与分离(真)创建的,所以当线程终止我们并不需要一些处理。 消息队列被明确地销毁。 下面是一些例子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 ,也不能安全使用与中断的解决方案。 另外,最后一个参数是不踏实。 这是所有留给读者作为练习为读者实现这些额外的要求和相应的备用路径。



文章来源: Prolog findall Implementation