【问题标题】:How can I simulate a soft cut in Prolog?如何在 Prolog 中模拟软剪辑?
【发布时间】:2016-11-15 21:58:05
【问题描述】:

如何模拟soft cut I *-> T; ISO Prolog中的E?我有副作用,所以我可以多次调用它。

除了最后一个要求,我认为以下定义有效:

if_(I, T, E) :-
    not(not(I)) ->
    call((I, T));
    call((not(I), E)).

(我实际上正在使用 XSB prolog;XSB 的解决方案对我也很有用。)

【问题讨论】:

  • 宁可使用if/3,就像 SICStus 一样。另外,为什么你需要这个结构?请注意,您不会获得单调性。它与 Prolog 风格的否定有类似的缺陷。
  • 我想知道是否不能使用 XSB 的表格功能来做到这一点。

标签: prolog porting iso-prolog prolog-cut xsb


【解决方案1】:

Yes, we can 在 ISO Prolog 甚至 XSB 中实现了这一点,但效率不高。为了提高效率,您需要一些“选择性切割”。此外,XSB 没有实现符合 ISO 标准的整数,因此必须单独处理溢出。

:- dynamic(if_counter/1).

if_counter(0).

:- dynamic(no_if_answer/1).
if(If_0, Then_0, Else_0) :-
   once(if_counter(Id)),
   Idx is Id+1,
   (  Idx > Id -> true
   ;  throw(error(representation_error(max_integer),
               'XSB misses ISO conforming integers'))
   ),
   retractall(if_counter(_)),
   asserta(if_counter(Idx)),
   asserta(no_if_answer(Id)),
   (  If_0,
      retractall(no_if_answer(Id)),
      Then_0
   ;  retract(no_if_answer(Id)) ->
      Else_0
   ).

效率低下的主要原因是对于一个确定的条件If_0,还有一个选择点。 难以想象,一旦执行了 retractall(no_if_answer(Id)),实现可能会得出结论:retract(no_if_answer(Id)) 将始终失败,但我怀疑实现者会投资于此类优化。编辑:这看起来不太可能的原因是实现必须保证断言的数字总是上升。

请注意,软切割会产生与切割相同的不完整性。考虑:

| ?- if(X = a, T = equal, T = not_equal).

X = a
T = equal;

no

这显然错过了答案!要了解原因,请使用X = b

| ?- X = b, if(X = a, T = equal, T = not_equal).

X = b
T = not_equal;

no
| ?- if(X = a, T = equal, T = not_equal), X = b.

no % bad!!

连接应该是可交换的(模不终止、错误、副作用)。

如果您对声明性健全的条件句感兴趣,这些条件句也非常有效且通常比不纯的条件句更快,请考虑if_/3。请参阅library(reif) 获取所有正确答案的 SICStus:

| ?- if_(X = a, T = equal, T = not_equal).
X = a,
T = equal ? ;
T = not_equal,
prolog:dif(X,a) ? ;
no

【讨论】:

  • 如果软剪辑参数没有留下选择点,那么软剪辑也不应该留下选择点。请参阅 SWI 和 Jekejeke 行为。
【解决方案2】:

好的,让我们发挥创意...您本质上需要一种方法来记住(通过回溯)If 条件至少有一个解决方案。动态谓词对我来说是一个禁忌,但还有其他选择吗?那么,ISO-Prolog 定义了一种匿名对象,stream-term,它可以(ab)用于以这种相当优雅的方式实现不可回溯标志:

if(If, Then, Else) :-
    open(., read, S),
    (
        If,
        close(S, [force(true)]),
        Then
    ;
        catch(close(S), error(existence_error(stream,_),_), fail),   % fail if already closed
        Else
    ).

我们关闭流以表明If 有一个解决方案,然后由 else 分支中的关闭尝试检测到。这在像ECLiPSe 这样的系统中完美且无泄漏。然而,许多系统(包括 XSB)重复使用封闭流的标识符(ISO 并未禁止),使得该解决方案不可移植。

但是等等,流有一个 position 属性,它可以设置,并且在回溯过程中保持它的值!使用这个技巧,XSB 上的以下工作:

if(If, Then, Else) :-
    % open('ReadableAndNonemptyFile', read, S),      % general ISO
    open(atom(a), read, S),                          % XSB (needs no file)
    stream_property(S, position(Zero)),
    get_char(S, _),
    (
        catch(If, Ball, (close(S),throw(Ball))),
        set_stream_position(S, Zero),
        Then

    ; stream_property(S, position(Zero)) ->
        close(S),
        fail
    ;
        close(S),
        Else
    ).

遗憾的是,open(atom(...),...) 功能是特定于 XSB 的,对于严格的 ISO-Prolog,您需要一个虚拟文件...

【讨论】:

  • 这是一个非常聪明的解决方案。当我将它放入我的应用程序时,它试图同时打开两次“a”但失败了。我递归地使用 if ,这就是我想象的问题所在。有没有办法为每次 if 调用打开一个新的流?
  • 前者在 XSB 中产生 permission_error(open,file,.),在 SICStus 中产生 system_error,但 GNU 接受这个,但只有 1023 次...
  • @EdMcMan:它确实在每次调用时都会打开一个新流,但 XSB 似乎对打开的原子流有一个小的限制(在我的 XSB 3.7 中为 4)。如果您改为打开文件,问题就会消失。
  • 后者仅适用于 XSB 中的 4 个同时实例。那么,open(atom(a), read, S). 就是一个错误。
【解决方案3】:

问题是,软剪辑应该相当聪明,但不应该 当它的论点没有留下选择点时,留下一个选择点。

SWI-Prolog 中没有选择点:

   Welcome to SWI-Prolog (threaded, 64 bits, version 8.1.4)

   ?- X=1 *-> Y=1; true.
   X = Y, Y = 1.
   ?- 

Jekejeke Prolog 中没有选择点:

   Jekejeke Prolog 3, Runtime Library 1.3.6

   ?- X=1 *-> Y=1; true.
   X = 1,
   Y = 1
   ?- 

到目前为止,这里公认的创造性解决方案都没有存档,因此它们都不能有效地替代原生实现。

Jekejeke Prolog 执行 determinism check,然后 删除析取选择点。否则,它标志着 析取选择点。从模块“逻辑”:

:- set_predicate_property(;/2, sys_nobarrier).
A *-> B; C :- sys_local_cut, sys_soft_cond(A, B, C).

:- set_predicate_property(sys_soft_cond/3, sys_nobarrier).
sys_soft_cond(A, B, _) :- sys_safe(A), sys_soft_local_cut, B.                        
sys_soft_cond(_, _, C) :- C. 

【讨论】:

    【解决方案4】:

    您的定义没有实现 soft-cut 语义:当测试成功时,您可以回溯到它。这是一个有用的控制结构(我使用它,例如在 Logtalk 中实现 coduction),但遗憾的是不能在 Prolog 级别以 可移植 方式实现,当然也不能在 ISO Prolog 标准的限制范围内实现。好消息是越来越多的 Prolog 系统实现了这种控制结构。这些包括,无特定顺序,SWI-Prolog、YAP、SICStus Prolog、GNU Prolog、CxProlog、ECLiPSe、Jekejeke Prolog 和 Ciao。但是请注意,虽然某些系统使用 *->/2 运算符,但少数(SICStus Prolog 和 Ciao)使用 if/3 谓词(YAP 两者都有)。此外,在极端情况下语义会有所不同(Logtalk 发行版包括一个 Prolog 一致性套件,该套件还检查 *->/2 变体)。

    【讨论】:

    • 除了共归纳之外,(*->/2)还有更多的用例吗?
    猜你喜欢
    • 2011-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多