Forall / 3手工

时间:2016-10-17 09:16:49

标签: prolog

我希望有一个简单的函数,它可以获取一种类型的所有事实并列出它:

% Facts
fact('a','1').
fact('b','2').
fact('c','3').

% Call
all_facts(L) :- ......

% Expected
27 ?- all_facts(L).
L = [ ('a', '1'), ('b', '2'), ('c', '3')].

我知道forall / 3已经很好了,可能是任何现实场景中的首选用法:

all_facts(L) :- findall(
                        (LETTER, NUMBER),
                        fact(LETTER, NUMBER),
                        L
                       ).

但我并没有尝试在此处实现此功能。我想要理解它背后的逻辑,因为我对Prolog来说相对较新。到目前为止,我在这里:

all_facts([(LETTER, NUMBER)|Rest]) :- fact(LETTER, NUMBER), fail.

这会按顺序通过所有事实,因为它会一直失败。我的问题是将它们实际保存在列表中。

1 个答案:

答案 0 :(得分:3)

正如@mat在Prolog的书中提出的那样你可以写:

all_facts( Template, Enumerator, List ) :-
        asserta( 'find all'( [] ) ),
        call( Enumerator ),
        asserta( 'find all'( {Template} ) ),
        fail
    ;
        'all found'( [], List ).

'all found'( SoFar, List ) :-
    retract( 'find all'( Item ) ),!,
    'all found'( Item, SoFar, List ). 

'all found'( [], List, List ).

'all found'( {Template}, SoFar, List ) :-
    'all found'( [Template|SoFar], List ).

示例:

?- all_facts((X,Y),fact(X,Y),L).
L = [ (a, '1'), (b, '2'), (c, '3')].

这背后的基本思想是静态地(从事实/ 2)断言从文件加载的术语,但是动态地(使用断言)以便能够在使用它们时收回它们。