Prolog中列表连接程序的声明性解释

Prolog中列表连接程序的声明性解释,prolog,declarative,Prolog,Declarative,我有一个非常简单的问题:编写一个Prolog程序,实现append Prolog函数,将两个字符串连接起来,并以以下方式工作: myappend1([],L,L). myappend1([X|L1],L2,[X|L3]) :- myappend1(L1,L2,L3). myappend2([],L,L). myappend2(L1,L2,L3) :- L1=[X|T], % Dimostra questo predicato AND

我有一个非常简单的问题:编写一个Prolog程序,实现append Prolog函数,将两个字符串连接起来,并以以下方式工作:

myappend1([],L,L).

myappend1([X|L1],L2,[X|L3]) :- myappend1(L1,L2,L3).
myappend2([],L,L).

myappend2(L1,L2,L3) :-  L1=[X|T],               % Dimostra questo predicato AND
                    L3=[X|L4],      % Dimostra questo predicato AND
            myappend2(T,L2,L4).     % Dimostra questa funzione
  • 追加([a,b],[c,d],X)。-->X=[a,b,c,d]
  • 附加([a,b],X[a,b,c,d])。-->X=[c,d]
  • 附加([a,b],[X,d],[a,b,c,d])。-->X=c
  • 附加(X,Y[a,b,c,d])。-->X=[]和Y=[a,b,c,d)
  • 因此,我有以下两种解决方案,我不确定我的声明性解释是否正确:

    1)解决方案1:

    myappend1([],L,L).
    
    myappend1([X|L1],L2,[X|L3]) :- myappend1(L1,L2,L3).
    
    myappend2([],L,L).
    
    myappend2(L1,L2,L3) :-  L1=[X|T],               % Dimostra questo predicato AND
                        L3=[X|L4],      % Dimostra questo predicato AND
                myappend2(T,L2,L4).     % Dimostra questa funzione
    
    我认为我可以用声明的方式阅读它,如下所示:

    事实表明:如果第一个列表(L1)是空的,而第二个列表(L2)不是空的,那么L1*L2的串联是L2,这是真的

    如果事实不是真的,则意味着第一个列表不是空的,因此第一个列表和第二个列表的连接不是真的,即第二个列表

    因此,让我调用第一个列表L1、第二个列表L2和第三个列表L3,如果L3是L1和L2的串联,则规则响应TRUE,否则为false

    我认为这个规则的声明意义是:如果规则的主体是真的,那么规则的主体是真的

    • 在head中,从L1列表和L3列表中提取第一个X元素(并尝试统一,如果继续匹配,则表示第三个列表不是第一个和第二个列表的串联)
    • 在body中,调用第一个列表上的函数(不含X元素)、第二个列表和L3列表(表示连接)
    当它到达基本情况时,我已证明事实myappend1([],L,L).这是真的,程序在上一次执行回溯,因为第一个列表的X元素与第三个列表的X元素统一,所以它也可以执行此操作。此计算过程为真,并返回,直到到达第一个断言

    这是正确的陈述式解释吗

    2)第二种解决方案:

    myappend1([],L,L).
    
    myappend1([X|L1],L2,[X|L3]) :- myappend1(L1,L2,L3).
    
    myappend2([],L,L).
    
    myappend2(L1,L2,L3) :-  L1=[X|T],               % Dimostra questo predicato AND
                        L3=[X|L4],      % Dimostra questo predicato AND
                myappend2(T,L2,L4).     % Dimostra questa funzione
    
    与前面的解决方案一样,事实只是说:如果第一个列表(L1)是空的,而第二个列表(L2)不是空的,L1*L2的串联是L2,这是真的

    如果事实不是真的,则意味着第一个列表不是空的,因此第一个列表和第二个列表的连接不是真的,即第二个列表

    如果事实不是真的,Prolog调用规则,此规则意味着:如果规则体为真,则规则头为真

    在这种情况下,我可以这样读:

    如果满足以下条件,则L1和L2的串联为L3为真:

    • L1的当前第一个X元素与在第一个子列表、L2和第三个子列表上调用的连接列表和myappend2的当前第一个元素相一致。这是真的
    对吗


    对我来说,用声明的方式进行推理是非常困难的:(

    就像上次一样,您添加了代码中没有的限制。不要为此感到难过,Prolog非常不同,需要时间来适应它

    让我们开始吧

    append([], L, L).
    
    你说:

    如果第一个列表(L1)为空,而第二个列表(L2)不为空,则L1*L2的串联确实为L2

    事实上,这条规则并没有说明L2是否为空——或者甚至是一个列表!——或者不是。它只是说附加到其他内容上的空列表就是其他内容。注意:

    ?- append([], foo, X).
    X = foo.
    
    这里的声明性阅读是“附加到L的空列表是L。”

    如果事实不是真的,则意味着第一个列表不是空的,因此第一个列表和第二个列表的连接不是真的,即第二个列表

    是的,这是正确的,但是Prolog并没有深入到身体中去。它只是说“第一个列表不是空的,所以这个规则不匹配;继续。”

    下一条规则:

    myappend1([X|L1], L2, [X|L3]) :- myappend1(L1,L2,L3).
    
    你的评论对我来说太复杂了。我想说,这条规则说:“如果列表L1到L2的我的附录1是L3,那么列表[X后接L1]到L2的我的附录1就是列表[X后接L3”。”然而,这一解读的结果与你描述的完全一样

    因此,您对第一个版本中发生的事情的理解是正确的

    机械地说,第二个解决方案与第一个解决方案完全相同。唯一的区别是,我们将统一从条款的开头移到了正文中。在我看来,这个版本显然较差,因为它所做的只是为读者创造额外的工作

    到目前为止,我认为你面临的问题是,你的声明性推理与Prolog的计算引擎密切相关。像我提供的那样,更纯粹的声明性阅读更简单,看起来更像Prolog所说的内容(与如何评估无关)

    你需要练习来区分这些概念,但我认为这会帮助你变得更好(显然这是你关心的事情)。与此同时,像你困惑时那样来这里寻求帮助没有什么错。:)


    如果我能提供更多帮助,请告诉我!

    就像上次一样,您正在添加代码中没有的限制。不要为此感到难过,Prolog非常不同,需要时间才能习惯

    让我们开始吧

    append([], L, L).
    
    你说:

    如果第一个列表(L1)为空,而第二个列表(L2)不为空,则L1*L2的串联确实为L2

    事实上,这条规则并没有说明L2是否为空——或者甚至是一个列表!——或者不是。它只是说附加到其他内容上的空列表就是其他内容。注意:

    ?- append([], foo, X).
    X = foo.
    
    这里的声明性阅读是“附加到L的空列表是L。”

    如果事实不是真的,那就意味着