【问题标题】:What is redo in Prolog when you trace?跟踪时 Prolog 中的重做是什么?
【发布时间】:2019-04-12 08:07:46
【问题描述】:

我有这段代码(迭代深化以找到最短路径):

arc(a, g).
arc(a, b).
arc(b, g).

path(X, Z, Path) :-
    length(Path, _),
    path_r(X, Z, Path).

path_r(Z, Z, []).
path_r(X, Z, [X|Path]) :-
    arc(X, Y),
    path(Y, Z, Path).

当我追踪它时,它给了我一条痕迹:

    2    2  Redo: length([],0) ? 

这里发生了什么? 另外,该行左侧的 2 2 是什么?

其余的追踪:

  1    1  Call: path(a,g,_23) ? 
  2    2  Call: length(_23,_55) ? 
  2    2  Exit: length([],0) ? 
  3    2  Call: path_r(a,g,[]) ? 
  3    2  Fail: path_r(a,g,[]) ? 
  2    2  Redo: length([],0) ? 
  2    2  Exit: length([_80],1) ? 
  3    2  Call: path_r(a,g,[_80]) ? 
  4    3  Call: arc(a,_146) ? 
  4    3  Exit: arc(a,g) ? 
  5    3  Call: path(g,g,[]) ? 
  6    4  Call: length([],_158) ? 
  6    4  Exit: length([],0) ? 
  7    4  Call: path_r(g,g,[]) ? 
  7    4  Exit: path_r(g,g,[]) ? 
  5    3  Exit: path(g,g,[]) ? 
  3    2  Exit: path_r(a,g,[a]) ? 
  1    1  Exit: path(a,g,[a]) ? 

【问题讨论】:

  • “重做”表示 Prolog 是 backtracking
  • redo更好的搜索关键字是choice-point
  • 你给了我们谓词,但你开始的查询是什么?
  • 如果你能阅读 OCaml,那么 this 会展示它在 OCaml 中的工作原理。
  • @GuyCoder 查询是:路径(a,g,P)。

标签: debugging prolog trace shortest-path


【解决方案1】:

这不是评论,而是答案。

Redo: length([],0) ? 

这里发生了什么?

这是您的跟踪输出;我添加了标识符和行号以准确识别Trace 行。

Trace  1   1    1  Call: path(a,g,_23) ? 
Trace  2   2    2  Call: length(_23,_55) ? 
Trace  3   2    2  Exit: length([],0) ? 
Trace  4   3    2  Call: path_r(a,g,[]) ? 
Trace  5   3    2  Fail: path_r(a,g,[]) ? 
Trace  6   2    2  Redo: length([],0) ? 
Trace  7   2    2  Exit: length([_80],1) ? 
Trace  8   3    2  Call: path_r(a,g,[_80]) ? 
Trace  9   4    3  Call: arc(a,_146) ? 
Trace 10   4    3  Exit: arc(a,g) ? 
Trace 11   5    3  Call: path(g,g,[]) ? 
Trace 12   6    4  Call: length([],_158) ? 
Trace 13   6    4  Exit: length([],0) ? 
Trace 14   7    4  Call: path_r(g,g,[]) ? 
Trace 15   7    4  Exit: path_r(g,g,[]) ? 
Trace 16   5    3  Exit: path(g,g,[]) ? 
Trace 17   3    2  Exit: path_r(a,g,[a]) ? 
Trace 18   1    1  Exit: path(a,g,[a]) ?  

这是您的源代码;我添加了标识符和行号以准确识别FactPredicate 行。

Fact 1          arc(a, g).
Fact 2          arc(a, b).
Fact 3          arc(b, g).

Predicate 1,1   path(X, Z, Path) :-
Predicate 1,2      length(Path, _),
Predicate 1,3      path_r(X, Z, Path).

Predicate 2,1   path_r(Z, Z, []).

Predicate 3,1   path_r(X, Z, [X|Path]) :-
Predicate 3,2       arc(X, Y),
Predicate 3,3       path(Y, Z, Path).

说明

要了解下面对length/2 的调用,请参阅其他answer 的长评论。

Trace  1 is your initial query `path(a,g,X)`  
         Prolog unifies this with Predicate 1,1 `path(X, Z, Path)`  
         Prolog unifies `a` with `X`, `g` with `Z`, and `X` with `Path`  
Trace  2 is Predicate 1,2 `length(Path,_)`  
         Prolog unifies `_23` with `Path` and `_` with `_55`  
         Prolog then calls `length/2` and upon return  
        `Path` is unified with `[]` and `_` is unified with `0`  
Trace  3 `length(_23,_55)` is unified to `length([],0)`  
Trace  4 is Predicate 1,3 `path_r(X, Z, Path).  
         Prolog unifies `a` with `X`, `g` with `Z`, and `Path` with `[]`  
         Prolog calls Predicate 2,1  
Trace  5 is Predicate 2,1 `path_r(Z, Z, [])`  
         Prolog unifies `a` with `Z`  
         Prolog can not unify `g` with `Z` because `Z` is `a` and fails.  
Trace  6 is Predicate 1,2 `length(Path,_)` 
         Prolog knows `length([],0)` failed  
         Prolog redoes (REDO) the call to `length/2` 
Trace  7 is Predicate 1,2 `length(Path,_)` 
        `Path` is unified with `[_80]` and `_` is unified with `1`  
Trace  8 is Predicate 1,3 `path_r(X, Z, Path)`  
         Prolog unifies `a` with `X`, `g` with `Z`, and `Path` with `[_80]`  
         Prolog calls Predicate 3,1 it can not call Predicate 2,1 because `Path` which is `[_80]` can not unify with `[]`.
Trace  9 is Predicate 3,2 `arc(X,Y)`
         Prolog unifies 'a` with `X` and `_146` with `Y`
         Prolog calls Fact 1
Trace 10 is Fact 1 `arc(a, g).`
         Prolog unifies `a` with `a` and `g` with `Y`

我介绍了重做之外的几个步骤,以便您可以添加更多示例行,以便您可以根据自己的选择自行完成。

虽然该示例是一个非常简单的示例,但对于刚接触 Prolog 的学生来说,使用 length/2 确实会使其更难理解。

【讨论】:

    【解决方案2】:

    这是答案中的评论,因为它不适合评论。

    本程序中length(Path,_)的使用是为了生成不同长度的列表。

    如果你在 SWI-Prolog 中运行查询 length(X,N),你会得到。

    ?- length(List,N).
    List = [],
    N = 0 ;
    List = [_774],
    N = 1 ;
    List = [_774, _780],
    N = 2 ;
    List = [_774, _780, _786],
    N = 3 ;
    List = [_774, _780, _786, _792],
    N = 4 ;
    List = [_774, _780, _786, _792, _798],
    N = 5 
    

    注意如何返回一个增加长度的列表。当您想要生成列表的结果并且您不知道列表的长度或想要返回不同长度的列表时,这个常用的技巧就是这样做的。

    花几个小时查看StackOverflow 或其他地方的Prolog 示例中的其他代码,您会注意到length/2 的使用,因为您已经知道了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-01-18
      • 1970-01-01
      • 1970-01-01
      • 2020-10-21
      • 1970-01-01
      • 2010-11-14
      • 2021-02-05
      相关资源
      最近更新 更多