【问题标题】:Trace how Prolog finds result for query跟踪 Prolog 如何查找查询结果
【发布时间】:2021-08-31 16:35:57
【问题描述】:

我正在准备明天要参加的 AI 考试,但我被困在一个特定的 Prolog 问题上。

问题如下:

考虑以下程序:

r([], X, X).
r([X|Y], X2, X3) :- 
   r(Y, [X|X2], X3).

跟踪 Prolog 如何找到以下查询的结果:

? - r([1,2,6], [], L).

我们必须手动追踪这个,我记得小部分,我在Prolog中写了这个并得到了答案,但看不到答案来自哪里。

P。 S. 我使用了 trace 运算符,它向我显示了步骤,但没有显示触发了哪些函数。

谢谢大家!

【问题讨论】:

    标签: debugging prolog trace


    【解决方案1】:

    如果您将跟踪捕获到本节之后概述的文件中,然后将行注释添加到您的代码并将代码行与跟踪相关联,您将获得类似的结果。

    r([1,2,6], [], L)        % Goal
    
    r([], X, X).             % Line 1
    r([X|Y], X2, X3) :-      % Line 2
       r(Y, [X|X2], X3).     % Line 3
    
    Call:  (11)       r([1, 2, 6], []       , _32640   )  % Goal
    Unify: (11)       r([1, 2, 6], []       , _32640   )  % Line: 2 
    Call:    (12)     r([2, 6]   , [1]      , _32640   )  % Line: 3 
    Unify:   (12)     r([2, 6]   , [1]      , _32640   )  % Line: 2
    Call:      (13)   r([6]      , [2, 1]   , _32640   )  % Line: 3
    Unify:     (13)   r([6]      , [2, 1]   , _32640   )  % Line: 2
    Call:        (14) r([]       , [6, 2, 1], _32640   )  % Line: 3
    Unify:       (14) r([]       , [6, 2, 1], [6, 2, 1])  % Line: 1
    Exit:        (14) r([]       , [6, 2, 1], [6, 2, 1])  % Line: 1
    Exit:      (13)   r([6]      , [2, 1]   , [6, 2, 1])  % Line: 3
    Exit:    (12)     r([2, 6]   , [1]      , [6, 2, 1])  % Line: 3
    Exit:  (11)       r([1, 2, 6], []       , [6, 2, 1])  % Line: 3
    

    使用protocol/0 将跟踪捕获到文件。

    文件:examples.pl

    :- module(examples,
        [
            example/1
        ]).
    
    r([], X, X).
    r([X|Y], X2, X3) :-
       r(Y, [X|X2], X3).
    
    example(1) :-
        r([1,2,6], [], L),
        format('~w~n',[L]).
    

    示例运行

    Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.28-20-g6f8a68f2b)
    SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
    Please run ?- license. for legal details.
    
    For online help and background, visit https://www.swi-prolog.org
    For built-in help, use ?- help(Topic). or ?- apropos(Word).
    
    ?- working_directory(_,'C:/Users/Groot').
    true.
    
    ?- [examples].
    true.
    
    ?- set_prolog_flag(color_term,false).
    true.
    
    ?- leash(-all), visible(+all).
    true.
    
    ?- protocol("./trace_output.txt").
    true.
    
    ?- trace.
    true.
    
    [trace]  ?- example(1).
       Call: (10) examples:example(1)
       Unify: (10) examples:example(1)
       Call: (11) examples:r([1, 2, 6], [], _32640)
       Unify: (11) examples:r([1, 2, 6], [], _32640)
       Call: (12) examples:r([2, 6], [1], _32640)
       Unify: (12) examples:r([2, 6], [1], _32640)
       Call: (13) examples:r([6], [2, 1], _32640)
       Unify: (13) examples:r([6], [2, 1], _32640)
       Call: (14) examples:r([], [6, 2, 1], _32640)
       Unify: (14) examples:r([], [6, 2, 1], [6, 2, 1])
       Exit: (14) examples:r([], [6, 2, 1], [6, 2, 1])
       Exit: (13) examples:r([6], [2, 1], [6, 2, 1])
       Exit: (12) examples:r([2, 6], [1], [6, 2, 1])
       Exit: (11) examples:r([1, 2, 6], [], [6, 2, 1])
    ^  Call: (11) format('~w~n', [[6, 2, 1]])
    [6,2,1]
    ^  Exit: (11) format('~w~n', [[6, 2, 1]])
       Exit: (10) examples:example(1)
    true.
    
    [trace]  ?- nodebug.
    true.
    
    ?- noprotocol.
    true.
    

    文件:trace_output.txt

    true.
    
    ?- trace.
    
    
    true.
    
    [trace]  ?- example(1).
    
    
       Call: (10) examples:example(1)
       Unify: (10) examples:example(1)
       Call: (11) examples:r([1, 2, 6], [], _32640)
       Unify: (11) examples:r([1, 2, 6], [], _32640)
       Call: (12) examples:r([2, 6], [1], _32640)
       Unify: (12) examples:r([2, 6], [1], _32640)
       Call: (13) examples:r([6], [2, 1], _32640)
       Unify: (13) examples:r([6], [2, 1], _32640)
       Call: (14) examples:r([], [6, 2, 1], _32640)
       Unify: (14) examples:r([], [6, 2, 1], [6, 2, 1])
       Exit: (14) examples:r([], [6, 2, 1], [6, 2, 1])
       Exit: (13) examples:r([6], [2, 1], [6, 2, 1])
       Exit: (12) examples:r([2, 6], [1], [6, 2, 1])
       Exit: (11) examples:r([1, 2, 6], [], [6, 2, 1])
    ^  Call: (11) format('~w~n', [[6, 2, 1]])
    [6,2,1]
    ^  Exit: (11) format('~w~n', [[6, 2, 1]])
       Exit: (10) examples:example(1)
    true.
    
    [trace]  ?- nodebug.
    
    
    true.
    
    ?- noprotocol.
    

    【讨论】:

      【解决方案2】:

      如果您使用SWI prolog tracer,您可以逐步执行您的过程,如果需要,它将显示当前目标和回溯(调用堆栈的排序)。

      只需发出trace.,然后调用您的目标r([1,2,6], [], L).

      您可以通过按Enter逐步执行目标,并按g

      打印当前回溯

      您也可以使用图形跟踪器发出gtrace. 而不是trace.。使用图形跟踪器可以让您查看调用堆栈和每个帧的变量绑定。

      要结束追踪,您可以致电nodebug.

      【讨论】:

      • 谢谢Gus,我知道trace 操作,但之前没有使用gtrace。我的问题是我发现很难理解跟踪本身。我们的讲师向我们展示了如何手动完成,我了解流程的逻辑,但不了解手动跟踪步骤。
      • 在您的示例中,“缺少”的是当序言处理器在执行递归调用时测试第一个子句时,它仍然不是基本情况。从理论上讲,它会尝试将例如 [2,3] 与 [] 绑定,这将失败,然后尝试第二个子句。除此之外,如果您询问,跟踪器将准确显示您的位置、变量绑定和回溯。
      • 请注意,我是从实际角度回答的(使用调试器)。要了解如何手工“在纸上”进行操作,我相信您最好阅读有关该主题的书籍章节。
      • 这正是我的问题,跟踪器没有显示它跳过了第一个子句。我已经写了一个例子,但你提到这真的很有帮助。主要问题,在第二个子句中,Prolog 是否会在进入函子本身之前首先将列表拆分为 r([X|Y)... 中的变量?
      • 看起来很棘手,这里是一个草图。 Prolog 会尝试将调用Y 中的第一个参数与第一个子句[] 的头部的第一个参数统一起来。现在假设Y 在具有[2,6] 的第一个递归调用中。所以它确实是一个术语./2(一个带有头部2和尾部[6]的列表)所以它不会与术语[]/0统一,因为它们有不同的函子,所以它会尝试第二个子句是术语./2(一个带有头部X和尾部Y的列表。现在它们具有相同的函子和数量,因此它将X2Y与@统一987654344@。其他参数/​​参数的绑定继续。
      猜你喜欢
      • 1970-01-01
      • 2016-04-05
      • 2016-02-02
      • 1970-01-01
      • 1970-01-01
      • 2013-04-27
      • 1970-01-01
      • 2016-01-06
      • 1970-01-01
      相关资源
      最近更新 更多