【问题标题】:Predicate control in PrologProlog 中的谓词控制
【发布时间】:2011-05-06 03:03:35
【问题描述】:

对 Prolog 谓词控制有兴趣。

假设我有一个谓词 f(A,X) 和 g(B)。

f(A,X):- a,b,c, g(X).
g(B):- true.

a - returns true
b - returns true.
c - returns false.
where a,b and c are random predicates.

如果 c 返回 false,我如何继续评估谓词 f(A,X) 中的 g(X)

【问题讨论】:

    标签: prolog predicate


    【解决方案1】:

    如果您的意图是定义f(A,X),以便无论c 是否失败,都应该评估g(X),那么:

    1. 您可以使用蕴含 (->) 和/或析取 (;)、对其进行编码
    2. f(A,X) 不需要根据c 定义。这假设c 没有副作用(例如,使用assert 断言数据库事实,或将IO 打印到流中)会改变环境并且在c 失败时无法撤消,在这种情况下,第一个选项更可取。

    使用析取有几种替代方法,例如:

    f(A,X) :- ((a, b, c) ; (a, b)), g(X).
    

    这个定义(上面)根本不依赖于c,但它总是会执行c(只要ab成功)。如果 c 完全失败,则析取 (;) 允许 PROLOG 回溯以尝试执行 a, b 再次,并继续执行 g(X)。请注意,这相当于:

    f(A,X) :- a, b, c, g(X).
    f(A,X) :- a, b, g(X).
    

    为了使 PROLOG 不会因为每次评估的第二个(相同的)头谓词 f(A,X) 而回溯两次评估 f(A,X),如果您的实现支持它,您可以选择放置一个剪切 (!) ,紧接在第一个子句中的c 子目标之后。剪切被放置在c 之后,因为如果c 失败,我们不希望解释器承诺f(A,X) 子句的选择,相反,我们希望解释器失败这个子句并尝试下一个子句,有效地忽略c并继续处理g(X)

    另请注意,此解决方案依赖于没有副作用的ab,因为当c 失败时,ab 会再次执行。如果abc都有副作用,可以试试implication

    f(A,X) :- a, b, (c -> g(X) ; g(X)).
    

    无论c 是否失败,这也将始终有效地执行g(X),如果c 失败,则不会再次执行ab。这个单子句定义也不会像前面的建议那样留下选择点。

    【讨论】:

      【解决方案2】:

      我猜你可以将c 包裹在ignore/1 中。考虑例如

      ?- false, writeln('Hello World!').
      false.
      
      ?- ignore(false), writeln('Hello World!').
      Hello World!
      true.
      

      但是,如果c 失败了,为什么还要继续呢?有什么用例?

      我在 SWI-Prolog 中测试了这段代码,我不确定其他 Prolog 是否有 false/0ignore/1。 后者可以这样定义:

      ignore(Goal) :- Goal, !.
      ignore(_).
      

      【讨论】:

      • +1 询问为什么这会有用。可移植的故障谓词是fail,顺便说一句。 (实现起来很简单:fail :- 0=1.
      • 如果c 失败,您可能希望继续的一种情况是c副作用;有关详细信息,请参阅我对这个问题的回答。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多