首页 文章

Prolog谓词不起作用

提问于
浏览
0

我和Prolog完全混淆了 . 我有两个简单的谓词,我试图弄清楚,但似乎无法让他们正确 . 首先,我试图找出一个删除谓词的变体,我需要从List1中删除给定元素的所有出现,并查看它是否等于List2 .

这是我试过的 .

del(S,[P],[P]).
del(S,[S],[]).
del(S,[H1,H2|T],L2) :- H1 = S, del([H2|T],L2).
del(S,[H1,H2|T],[H1,T2]) :- H1 \= S, del([H2|T],T2).

另一个谓词采用两个列表,并在List1中取出所有出现的元素2,并将其替换为4,并查看List1是否与List2相同 . 为了简化,没有子列表 .

这些是我尝试过的 .

change([],[]).
change([H1,H2|T],L) :- H1 = 2, append([2],L), change([H2|T],L).
change([H1,H2|T],L) :- H1 \= 2, append(H1,L), change([H2|T],L).

我想知道我所犯的错误,也许是对这些术语如何起作用的解释 . 谢谢 .

2 回答

  • 1

    Examination of del/3

    (1) del(S,[P],[P]).
    (2) del(S,[S],[]).
    (3) del(S,[H1,H2|T],L2) :- H1 = S, del([H2|T],L2).
    (4) del(S,[H1,H2|T],[H1,T2]) :- H1 \= S, del([H2|T],T2).
    

    (1)此规则表示列表 [P] 是列表 [P] ,其中删除了元素 S . 此规则的问题是 SP 可能是相同的值,因此规则是't always true. If you wanted this to be true all the time (be a valid rule), you' d需要规定 SP 不能实例化为相同的值:

    del(S, [P], [P]) :- S \= P.
    

    这假设我们甚至需要这个规则,但我们暂时将它留在这里,因为在这个新状态下,它是正确的 .

    (2)此规则表示 [] 是列表 [S] ,其中元素 S 已删除 . 那是真实的 .

    (3)此规则表示 L2[H1,H2|T] 列表,如果 H1S 统一, L2 删除 L2 ,则删除了 S . 但是,有一个缺失的论点 . 你有 del([H2|T], L2) 但是 del/3 被定义为接受3个参数 . 我们假设你的意思是 S 是第一个参数( S 仍然是被删除的东西),所以 del(S, [H2|T], L2) . 新修复的规则似乎是合乎逻辑的 .

    (4)此规则说* [H1,T2] 是列表 [H1,H2|T] ,如果 H1S 不一致,则删除元素 ST2 是删除元素 S 的列表 [H2|T] . 这与#3有相同的问题,缺少 del/3 的参数,我们再次假设它是 S ,使它成为 del(S, [H2|T], T2) . 另一个问题是你有 [H1,T2] ,它只是两个元素的列表: H1T2 . 另一个错字 . 这应该是 [H1|T2] . 所以修复后的规则现在似乎有意义了 .

    修复这些粗心的错误会导致你的谓词几乎正常工作!当第一个参数被实例化时,它将产生正确的结果:

    | ?- del(a, [a,b,c,a,d,a], L).
    
    L = [b,c,d] ? a
    
    no
    

    此外,它可以清理一下 . H2 并未真正用于第3和第4个子句中 . 在第3个子句中,您可以在谓词的头部实例化 SH1 . 那么这两个成了:

    (3) del(S, [S|T], L2) :- del(S, T, L2).
    (4) del(S, [H|T], [H|T2]) :- H \= S, del(S, T, T2).
    

    列表上的谓词无效 . 我不确定这是否是故意的,但你可以说 del(X, [], []) 应该是真的(当你从空列表中删除一个元素时会产生一个空列表) . 如果我们包含此规则:

    (1a) del(_, [], []).
    

    我们现在可以摆脱规则(1)和(2),因为(3)和(4)将处理它们并递归到规则(1a) .

    此外,在这种情况下,规则仍然失败:

    | ?- del(X, [a,b,c], [a,c]).
    
    no
    

    如果这样做会很好, X = b . 问题出现在第(4)条中,我们检查 H \= S ,这意味着 HS 不是统一的 . 如果 S 是变量,则此表达式对我们起作用,因为 H \= S 将始终失败(因为 S 确实可以统一为 H ) . 所以我们用 dif(H,S) 替换它来检查这些术语是否相同 . 有些Prologs不提供 dif/2 ,在这种情况下,您可以用 \== 代替此解决方案( H \== S ) . 我们得到的规则集是:

    (1) del(_, [], []).
    (2) del(S, [S|T], L2) :- del(S, T, L2).
    (3) del(S, [H|T], [H|T2]) :- dif(H, S), del(S, T, T2).
    

    让我们“重读”这些规则:

    • 从空列表中删除的任何元素都是空列表 .

    • 删除了元素 S 的列表 [S|T] 是列表 L2 如果 L2 是列表 T ,其中元素 S 已删除 .

    • 列表 [H|T2] 是列表 [H|T] ,如果 SH 不同,则删除元素 ST2 是删除元素 S 的列表 T .

    这看起来简单得多,虽然只是几个简单的reworks远离原始 . 它现在会产生这个结果,这很好:

    | ?- del1(X, [a,b,c,b,d], [a,c,d]).
    
    X = b ? ;
    
    (1 ms) no
    

    Examination of change/2

    (1) change([],[]).
    (2) change([H1,H2|T],L) :- H1 = 2, append([2],L), change([H2|T],L).
    (3) change([H1,H2|T],L) :- H1 \= 2, append(H1,L), change([H2|T],L).
    

    (1)这条规则说如果我们改变空列表中的所有2,我们得到空列表 . 听起来不错 .

    (2)这条规则说如果我把列表 [H1,H2|T] 并且我更改了2 's to 4' s,如果 H1 是2,我会得到 L 并将 L 追加到 [2] (由于 [2] 不可变,因此总是会失败 - 请参阅 append/2append/3 的在线文档! append/2 是附加列表,例如)和 L[H2|T] ,其中包含2个's changed to 4' . 这已经不会改变2 's to 4'为什么我要为 [2] 追加一些东西?我们需要丢失 append 并简单地将 L 统一为 [4|T2] ,其中 T2[H2|T] 及其2 's changed to 4' . 或者换句话说:

    (2) change([H1,H2|T], L) :- H1 = 2, L = [4|T2], change([H2|T], T2).
    

    这可以使用如上所述的在条款的头部中结合统一的方法进一步简化 . 另请注意,我们也没有真正使用 H2 在这里可见 . 所以 [H2|T] 可以只是 T

    (2) change([2|T], [4|T2]) :- change(T, T2).
    

    因此,如果有2,则使用4代替2,然后处理尾部 .

    (3)此规则与 append/2 查询具有相同的问题(2) . 我们可以遵循与规则(2)相同的模式,并修复不相等的检查:

    (3) change([H|T], [H|T2]) :- H \== 2, change(T, T2).
    

    因此,如果它不是2,我们只是继承元素 H ,然后处理尾部 . 完整的 change 谓词如下所示:

    (1) change([], []).
    (2) change([2|T], [4|T2]) :- change(T, T2).
    (3) change([H|T], [H|T2]) :- H \== 2, change(T, T2).
    

    重读规则,看到它们具有逻辑意义:

    • 在空列表中更改2 's to 4'是空列表 .

    • 在列表 [2|T] 中更改2 's to 4'是列表 [4|T2] ,如果 T2 是列表 T ,其中包含2 's changed to 4' .

    • 在列表 [H|T] 中更改2 's to 4'是列表 [H|T2] 如果 H 不是 2T2 是列表 T ,其中包含2 's changed to 4' .

  • 3

    让我们从最简单的两个开始: change/2 . 两个列表具有相同的长度,并且它们基本相同 - 对于2的出现是安全的,应该由4替换 . 因此,首先为这样的对定义关系:

    exch(2, 4).
    exch(X, X) :-
       dif(X, 2).
    

    您可以出于性能原因对此进行优化

    exch(A, B) :-
       (  A == 2 -> B = 4
       ;  A \= 2 -> A = B
       ;  A = 2, B = 4
       ;  A = B, dif(A,2)
       ).
    

    现在,您的实际定义是

    change(Xs, Ys) :-
       maplist(exch, Xs, Ys).
    

    或者更详细地说:

    change([], []).
    change([A|As], [B|Bs]) :-
       exch(A, B),
       change(As, Bs).
    

    要将此定义与建议的其他定义进行比较,请考虑以下查询:

    ?- change([X],[Y]).
    X = 2,
    Y = 4 ;
    X = Y,
    dif(Y, 2).
    

    del(E, Xs, Ys) :-
       tfilter(dif_truth, Xs, Ys).
    
    dif_truth(X, Y, true) :-
       dif(X, Y).
    dif_truth(X, X, false).
    
    tfilter(     _, [], []).
    tfilter(CT, [E|Es], Fs0) :-
       call(CT,E,Truth),
       (  Truth = false,
          Fs0 = Fs
       ;  Truth = true,
          Fs0 = [E|Fs]
       ),
       tfilter(CT, Es, Fs).
    

    Further uses

相关问题