在不使用内置Findall的情况下实现简单版本的Prolog Findall

发布于 2025-02-09 01:12:17 字数 730 浏览 3 评论 0 原文

我正在尝试在Prolog中实现一个简单的Findall版本,而无需使用内置的Findall或类似的内置谓词 - 就像学习练习一样。

例如,假设我的数据库中有一个关系a/1,

a(1).
a(11).
a(13).

我希望像find_the_as(list)这样的关系给我列表= [1,11,13]。

我可以使用断言和缩回的基于“失败”的循环来执行此操作,但是我认为必须有一种递归方法来使用累加器来执行此操作(而且我只是看不到它)。

提前致谢!

例如:

a(1)。
A(11)。
A(13)。

%
% collect all the N such that a(N) 
% into a List
%  
collect_n_such_that_a_of_n(List) :- 
   retractall(the_n_such_that_a_of_n(_)),
   assert(the_n_such_that_a_of_n([])),
   (
      a(N),
      the_n_such_that_a_of_n(As),
      retractall(the_n_such_that_a_of_n(_)),
      assert(the_n_such_that_a_of_n([N|As])),
      fail
   ) ; true,
   the_n_such_that_a_of_n(List).
   

I am trying to implement a simple version of findall in Prolog without using the built-in findall or similar built-in predicates -- just as a learning exercise.

For example, suppose there is a relation a/1 in my database,

a(1).
a(11).
a(13).

and I want a relation like find_the_as(List) to give me List = [1,11,13].

I can do this with a "fail" based loop using assert and retract, but I am thinking there must be a recursive way to do this using an accumulator (and I am just not seeing it).

Thanks in advance!

for example:

a(1).
a(11).
a(13).

%
% collect all the N such that a(N) 
% into a List
%  
collect_n_such_that_a_of_n(List) :- 
   retractall(the_n_such_that_a_of_n(_)),
   assert(the_n_such_that_a_of_n([])),
   (
      a(N),
      the_n_such_that_a_of_n(As),
      retractall(the_n_such_that_a_of_n(_)),
      assert(the_n_such_that_a_of_n([N|As])),
      fail
   ) ; true,
   the_n_such_that_a_of_n(List).
   

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

童话 2025-02-16 01:12:17

使用此示例:

a(1).
a(11).
a(13).

find(Input,Input) :- \+ (a(X), \+ memberchk(X,Input)).
find(Input,Output) :- a(X), \+ memberchk(X,Input), !, find([X|Input],Output). 

find_the_as(List) :- find([], List).

然后查询:

find_the_as(List).

返回:

List = [13, 11, 1]

示例使用:

与Findall不同,结果列表不包含重复项。例如。如果添加了额外的 a(11),则结果列表仍然只包含一个 11

与Findall不同,结果列表中的元素是相反的(即 [13,11,1] 而不是 [1,11,13] )。

Using this example:

a(1).
a(11).
a(13).

find(Input,Input) :- \+ (a(X), \+ memberchk(X,Input)).
find(Input,Output) :- a(X), \+ memberchk(X,Input), !, find([X|Input],Output). 

find_the_as(List) :- find([], List).

then the query:

find_the_as(List).

returns:

List = [13, 11, 1]

The example uses:

  • memberchk/2 - True if the first argument is a member of the list represented by the second argument.
  • \+/1 - True if the goal represented by its argument cannot be proven.

Unlike with findall, the resulting list does not contain duplicates. eg. if you add an extra a(11) then the resulting list will still only contain one 11.

Unlike with findall, the elements in the resulting list are in reverse order to which they were found (i.e. [13, 11, 1] rather than [1, 11, 13]).

时光瘦了 2025-02-16 01:12:17

使用 call_nth/2 ((当心具有副作用的程序):

findall_recursive(Template, Goal, Bag):-
  findall_recursive(Template, Goal, Bag, 1).
  
findall_recursive(Template, Goal, Bag, N) :-
    copy_term(Goal-Template, CGoal-CTemplate),
    (   call_nth(CGoal, N)
    ->  succ(N, N1),
        Bag=[CTemplate|Bag1],
        findall_recursive(Template, Goal, Bag1, N1)
    ;   Bag=[]
    ).

样本运行具有以下事实:

a(1).
a(11).
a(13).
a(11).

?- findall_recursive(X, a(X), Bag).
Bag = [1, 11, 13, 11].

Using call_nth/2 (beware of procedures which have side effects):

findall_recursive(Template, Goal, Bag):-
  findall_recursive(Template, Goal, Bag, 1).
  
findall_recursive(Template, Goal, Bag, N) :-
    copy_term(Goal-Template, CGoal-CTemplate),
    (   call_nth(CGoal, N)
    ->  succ(N, N1),
        Bag=[CTemplate|Bag1],
        findall_recursive(Template, Goal, Bag1, N1)
    ;   Bag=[]
    ).

Sample run having these facts:

a(1).
a(11).
a(13).
a(11).

?- findall_recursive(X, a(X), Bag).
Bag = [1, 11, 13, 11].
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文