如何在prolog中计算父母的子女数(不使用列表)?

如何在prolog中计算父母的子女数(不使用列表)?,prolog,Prolog,我有以下问题。我有一些事实,例如: 父母(简,迪克)。 父母(迈克尔,迪克)。 我想要一个谓词,比如: 儿童人数(迈克尔,X) 如果我这样称呼它,它表示X=1 我在网上搜索过,每个人都把孩子放在列表中,有没有不使用列表的方法?我只能找到两种方法来解决这个问题 第一个似乎更简单的方法是将所有的解决方案都列在一个列表中,然后进行计数。我不知道你为什么不喜欢这个选项。你是担心效率还是什么?还是仅仅是一项任务 问题是,如果不使用诸如setof/3之类的元逻辑谓词,您将不得不允许Prolog以通常的方式绑

我有以下问题。我有一些事实,例如: 父母(简,迪克)。 父母(迈克尔,迪克)。 我想要一个谓词,比如: 儿童人数(迈克尔,X) 如果我这样称呼它,它表示X=1


我在网上搜索过,每个人都把孩子放在列表中,有没有不使用列表的方法?

我只能找到两种方法来解决这个问题

第一个似乎更简单的方法是将所有的解决方案都列在一个列表中,然后进行计数。我不知道你为什么不喜欢这个选项。你是担心效率还是什么?还是仅仅是一项任务

问题是,如果不使用诸如
setof/3
之类的元逻辑谓词,您将不得不允许Prolog以通常的方式绑定值。如果让Prolog这样做,那么循环的唯一方法就是失败,如下所示:

numberofchildren(Person, N) :- parent(Person, _), N is N+1.
?- numberofchildren(michael, N)
N = 1 ;
N = 1 ;
N = 1 ;
no.
但这是行不通的;首先,您将得到未充分实例化的
参数。然后你要解决这个问题,得到如下结果:

numberofchildren(Person, N) :- parent(Person, _), N is N+1.
?- numberofchildren(michael, N)
N = 1 ;
N = 1 ;
N = 1 ;
no.
原因是,如果Prolog要一个接一个地检查事实,那么您需要使用Prolog来回溯,并且每次回溯时,它都会取消自上一个选择点以来绑定的任何内容。我所知道的通过此屏障传递数据的唯一方法是使用动态存储:

:- dynamic(numberofchildrensofar/1).

numberofchildren(Person, N) :- 
  asserta(numberofchildrensofar(0)), 
  numberofchildren1(Person), 
  numberofchildrensofar(N), !.

numberofchildren1(Person) :-
  parent(Person, _),
  retract(numberofchildrensofar(N)),
  N1 is N + 1,
  asserta(numberofchildrensofar(N1),
  !, fail.
numberofchildren1(_).
我还没有测试过这个,因为我觉得它相当恶心,但如果它不起作用的话,它可能会起作用


无论如何,如果可能的话,我强烈建议您选择列表选项。

计算解决方案的数量需要一些额外的逻辑工具(它本质上是非单调的)。这里有一个可能的解决方案:


:- dynamic count_solutions_store/1.

count_solutions(Goal, N) :-
    assert(count_solutions_store(0)),
    repeat,
    (   call(Goal),
        retract(count_solutions_store(SoFar)),
        Updated is SoFar + 1,
        assert(count_solutions_store(Updated)),
        fail
    ;   retract(count_solutions_store(T))
    ),
    !, N = T.

感谢Daniel的好意评论。我想说的是,用nb_setval/nb_getval(例如在SWI Prolog中提供)替换assert/retract可以获得300%的时间。例如
nb\u setval(count\u solutions\u store,0)