代码之家  ›  专栏  ›  技术社区  ›  David Tonhofer

Prolog中处理“剩余目标”的方法是什么?

  •  0
  • David Tonhofer  · 技术社区  · 3 年前

    room(green).
    room(blue).
    room(red).
    room(white).
    
    location(jimmy,red).
    location(ricky,blue).
    location(cindy,green).
    
    % "Is a certain room unoccupied?"
       
    not_occupied(Room) :-
       nonvar(Room),
       assertion(room(Room)),
       \+ location(_Person,Room).
    
    % If no specific "Room" has been given, the negated goal is
    % delayed until the "Room" has been instantiated.
    
    not_occupied(Room) :-
       var(Room),
       !,
       when(
          ground(Room),
          (\+ location(_Person,Room))
       ).
    

    如果我现在问

    ?- not_occupied(R).
    

    ?- not_occupied(R).
    when(ground(R),\+location(_7676,R)).
    

    实际上,事实并非如此 真正地 成功。它乐观地成功(因为为了不停止计算,它必须成功),但实际的逻辑成功取决于剩余目标的实际成功。

    如何以编程方式确定子目标是否成功地实现了剩余目标(那我该怎么办?)什么是方法?

    附笔。

    拥有第二个Prolog真值可能是一个很好的Prolog扩展,因为 true+ 会表明 “在剩余目标成功的条件下取得成功” . 这实际上似乎是有必要的:

    在SWI Prolog中,有一个固有的模棱两可的目标:

    do :- not_occupied(_).
    

    调用它甚至不会打印出任何剩余目标:

    ?- do.
    true.
    

    目标成功了吗?不完全是,它仍然处于逻辑的边缘,但是高层甚至没有告诉我。另一方面,没有办法将更多的信息输入到程序中,以解决剩余目标。但是因为计算结束而默认为“成功”的感觉是错误的。

    0 回复  |  直到 3 年前
        1
  •  0
  •   Mostowski Collapse ninesided    3 年前

    无法解析其剩余目标的查询称为挣扎查询。当计算打算成功或有限地失败时,它们可能会挣扎。剩余目标引入了第三种状态,既不是成功,也不是有限失败。

    约束逻辑程序可能无法调用某些约束解算器,因为变量的实例化或约束不够。为了避免在约束求解器中挣扎,它们通常提供标签作为最后手段。

    第三种状态出现在顶层,列出剩余目标。如何查询剩余目标取决于实现。典型的谓词有:

    • 调用变量(G,L):
      只要目标G成功并统一L,谓词就成功 新引入的属性变量。
    • 称之为残余物(G,L):
      只要目标G成功并统一L,谓词就成功 在新引入的属性变量的约束下。

    SWI-Prolog不在顶层打印剩余变量,这是SWI-Prolog提供的一个服务,只显示投影的变量。但是你永远不能查询剩余的:

    /* SWI-Prolog */
    ?- do.
    true.
    
    ?- call_residue_vars(do, X).
    X = [_5968],
    when(ground(_5968), \+location(_6000, _5968)).
    

    Pitty说SWI Prolog不支持call\u/2。复制\u term/3并不是真正的替代品。在我的Prolog系统中,我已经停止在顶层计算投影并显示所有东西。同时我也支持调用\u/2:

    /* Jekejeke Prolog */
    ?- do.
    when(ground([_A]), \+ location(_B, _A))
    
    ?- call_residue_vars(do, X).
    X = [_A],
    when(ground([_A]), \+ location(_B, _A))
    
    ?- call_residue(do, X).
    X = [when(ground([_A]), \+ location(_B, _A))],
    when(ground([_A]), \+ location(_B, _A))
    

    call\u/2也可以在ECLiPSe Prolog和SICStus Prolog中找到。在SICStus Prolog中,它返回一个成对列表,也显示主变量。另一方面,eclipseprolog只返回伪变量。还有一些call\u vars/2的兼容性问题,比如 here .

        2
  •  6
  •   false    3 年前

    ?- length(Xs, 0).
       Xs = [].
    

    在这里,答案是以 它描述了一个单一的解决方案。

    ?- length(Xs, 1).
       Xs = [_A].
    

    同样,这是一个答案替代,但这一次它描述了无限多的解决方案。

    通常,答案和解决方案的概念可以互换使用,但一旦我们使用延迟目标或约束,我们就需要一个明确的区分。现在的新情况是,答案可能包含任意数量的解决方案,包括一个都没有。

    ?- freeze(X, false).
       freeze(X,false).   % no solution
    
    ?- freeze(X, ( X = 1 ; X = 2 ) ).
       freeze(X,(X=1;X=2)).  % two solutions
    
    

    一些实现提供 frozen(Var, Goal) 只是为了实现与 Var . 在这种情况下,内置 call_residue(Goal_0, Residuum) 她怀孕了。最初,在sicstus0.7中,它是为延迟目标定义的,因为剩余量定义得很好。然而,一旦我们将我们的语言扩展到clpfd,事情就不那么清楚了。以下是SICStus 3.12.5:

    | ?- X in 1..3, call_residue(X in 2..4, Residuum).
    Residuum = [[X]-(X in 2..3),
    X in 1..3 ?
    

    X in 2..3 X in \{1} ? 事情可能变得相当复杂(阅读:buggy)。另外,撤消绑定也是一项相当大的工作;或者实现首先创建整个目标的副本,然后保留约束。

    SICStus 4已更换 call_residue/2 由两个新的内置。 call_residue_vars(Goal_0, Vars) 统一 Vars 与中创建的延迟目标或约束相关的变量 Goal_0 . 请注意,当某些约束变量在 目标0 目标0 . 但主要的一点是,这种内置的实现成本相对较低。它不复制 或其任何子项。

    另一个是 copy_term(Term, Copy, G_0s) 可以通过调用 maplist(call, G_0s) (瑞士语,Scryer)或 call(G_0) (在西斯图斯)。在SWI(clpfd)和Scryer(clpz)的实现中,表单的一些冗余约束 V in inf..sup 由投影省略。但投影实际上是另一个问题。