【问题标题】:Deducing facts from a set via a predicate by metaprogramming通过元编程通过谓词从集合中推断事实
【发布时间】:2013-02-13 09:25:36
【问题描述】:

假设我有一组文字(例如表示为一个列表)和一个动态指定的谓词,我想要生成一组文字,其中包含所有以前的文字,以及可以通过以下方式扣除的文字将谓词应用于集合。

一个例子,已经定义了谓词

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
  • 如果成功则断言其头部
  • 收集结果集中所有断言的事实并放入一个列表中

没有更好的办法吗?

更新 这个解决方案,由 CapelliC 更好地定义,通过使用元编程不能处理对象标识下集合中的变量。有什么解决方法吗?

【问题讨论】:

  • 您是否要根据谓词Pred 的(动态定义的)推理规则,用Set 的完整列表(闭包)填充DeducedSet?在这种情况下,DeducedSet 将始终由(初始)列表Set(可能由具有各种函子的项组成)后跟由函子Pred 的新项组成的尾部。通过引入累加器参数可能有助于在此类推理规则下找到闭包。
  • 是的,但为什么在这种情况下累加器会更有效?
  • 我想到的是,累加器可以很容易地构造DeducedSet,直到无法进行进一步的推断,然后“返回”已经组装的列表。我主要是在问您是否想要“关闭”或只是对您的DeducedSet 进行一次修改。
  • 我已经了解编程的简单性,我还想找到一个有效的解决方案来找到一个闭包,并可能在 OI 下处理 vars

标签: prolog metaprogramming


【解决方案1】:

您可以使用 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 了解“免费使用”且功能丰富的系统。

【讨论】:

  • 感谢您指向 Datalog,但我只需要使用 Prolog。要从集合中收回所有元素,我想调用:retract_set(Set) :- member(Literal, Set)、retract(Literal)、失败就足够了。收回设置(_)。
  • 这个解决方案(我猜一般是元编程)在我的集合中没有接地文字并且我假设 OI(对象标识)时显示了一个问题。例如 [base(X,Y), base(X,Z)] 将导致 pred(X,Z)
  • 这是一个困难的主题。我发布了一个“幼稚”的答案,尤其是因为您要求most efficient and general way。我认为“Datalog”评估可能是正确的答案,但在答案中我们可以尝试实现 naive 算法,这也可能相当困难。优化它当然成为一项艰巨的任务。
  • 我想我可以将所有文字保留为 const-var 关联,应用此方法,然后使用关联恢复到原始变量。虽然它增加了一点复杂性
猜你喜欢
  • 2020-05-20
  • 2012-05-19
  • 1970-01-01
  • 2014-01-11
  • 2014-10-26
  • 2019-03-17
相关资源
最近更新 更多