通过元编程通过谓词从集合中推导出事实

时间:2013-02-13 09:25:37

标签: prolog metaprogramming

假设我有一组文字(例如表示为列表)和一个动态指定的谓词,我想要的是产生一组文字,其中包含除了可以扣除的文字以外的所有文字。将谓词应用于集合。

一个例子,定义了谓词

pred(A, B) :- base(A, B).
pred(A, C) :- base(A, B), pred(B, C).

并假设谓词的这种签名

deduce_set(+Set, +Pred, ?DeducedSet)

以下陈述成立(是):

deduce_set([base(a,b), base(a,c), base(b,d), base(d, e)],
           pred/2,
           [base(a,b), base(a,c), base(b,d), base(d,e), pred(a,d), pred(a,e), pred(b,e)]
          ).

最有效和最通用的方法是什么?我一直在想类似的事情:

  • 在Set
  • 中声明所有文字
  • 致电Pred
  • 如果成功断言
  • 收集结果集中的所有断言事实并放入列表

是不是有更好的方法?

UPDATE 这个解决方案,由CapelliC更好地定义,使用元编程无法处理对象标识下的集合中的变量。对此有何解决方法?

1 个答案:

答案 0 :(得分:2)

您可以使用findall / 3(或更好,findall / 4),避免一些问题来区分(例如)在重试演绎步骤之前需要删除哪些pred / 2实例。

deduce_set(Base, Pred/Arity, Res) :-
    functor(P, Pred, Arity),

    % how to 'undo' this without a description?
    % retractall(base(_,_)),

    setof(F-A, M^(member(M, Base), functor(M, F, A)), Desc),
    maplist(retractdesc, Desc),

    maplist(assertz, Base),

    findall(P, P, All),
    append(Base, All, Res).

retractdesc(F-A) :-
    functor(P, F, A),
    retractall(P).

我还会添加一个Base元素的描述,以便在运行之前知道要清除什么(当然可以使用setof(F-A,M^(member(M,Base),functor(M,F,A)),Desc)获得)

pred(A, B) :- base(A, B).
pred(A, C) :- base(A, B), pred(B, C).

test :-
    deduce_set([base(a,b), base(a,c), base(b,d), base(d, e)], pred/2, R),
    R = [base(a,b), base(a,c), base(b,d), base(d,e), pred(a,d), pred(a,e), pred(b,e)].

请注意,test / 0将失败,因为返回集与预期列表不匹配。

?- test.
base(a,b)
base(a,c)
base(b,d)
base(d,e)
pred(a,b)
pred(a,c)
pred(b,d)
pred(d,e)
pred(a,d)
pred(a,e)
pred(b,e)
false.

一般来说,我建议使用Datalog来完成你的任务,因为非正式的描述似乎非常相似。有关“免费使用”和功能丰富的系统,请参阅DES