如果削减'!',执行的区别是什么?存在?

时间:2017-05-09 05:41:26

标签: prolog prolog-cut

counter([],[]).
counter([H|T],[[H,C1]|R]) :- counter(T,[[H,C]|R]),!, C1 is C+1.
counter([H|T],[[H,1]|R]) :- counter(T,R).

“!”的影响是什么?因为我在上面和下面的代码中输入相同的输出?

 counter([],[]).
 counter([H|T],[[H,C1]|R]) :- counter(T,[[H,C]|R]),C1 is C+1.
 counter([H|T],[[H,1]|R]) :- counter(T,R).

我是Prolog的新手。

3 个答案:

答案 0 :(得分:4)

这是我纯粹而有希望的高效解决方案:

counter([X|L], C):- counter(L, X, 1, C).

counter([],X, Cnt, [[X,Cnt]]).
counter([Y|L], X, Cnt, [[X,Cnt]|C]):-
  dif(X, Y),
  counter(L, Y, 1, C).
counter([X|L],X, Cnt, [[X,XCnt]|C]):-
  Cnt1 #= Cnt+1,
  Cnt1 #=< XCnt,
  counter(L, X, Cnt1, [[X,XCnt]|C]).

根据@false:

的建议使用if_3
counter([X|L], C):- counter(L, X, 1, C).

counter([],X, Cnt, [[X,Cnt]]).
counter([Y|L], X, Cnt, [[X,XCnt]|C]):-
  if_(X=Y,
    (
      Cnt1 #= Cnt+1,
      Cnt1 #=< XCnt,
      counter(L, X, Cnt1, [[X,XCnt]|C])
    ),
    (
      XCnt=Cnt,
      counter(L, Y, 1, C)
    )
  ).

答案 1 :(得分:3)

剪切运算符!通过修剪所有选择点来提交当前的派生路径。鉴于一些事实

fact(a).
fact(b).

你可以比较有和没有剪切的答案:

?- fact(X).
X = a ;
X = b.

?- fact(X), !.
X = a.

如您所见,通用查询现在仅报告其首次成功。仍然是查询

?- fact(b), !.
true.

成功。这意味着,该切割违反了,对逻辑连接的解释:

?- X = b, fact(X), !.
X = b.

?- fact(X), !, X=b.
false.

但是根据我们对连词的理解,A∧B应该在B∧A成立时准确保持。那为什么要这样呢?

  • 效率:可以使用剪切,这样它们只会更改执行属性,而不会更改谓词的答案。这些所谓的绿色削减例如在Richard O'Keefe的Craft of Prolog中描述。如上所述,保持带切割的谓词的正确性比没有切口的正确性要困难得多,但显然,正确性应该在效率之前。

    看起来您的问题是绿色的,但如果答案没有变化,我不能100%确定。

  • 否定:根据closed world assumption的逻辑否定用cut表示。您可以将neg(X)定义为:

    neg(X) :-
      call(X),
      !,
      false.
    neg(_) :-
      true.
    

    因此,如果call(X)成功,我们就会删除第二条规则的选择点并导出false。否则,什么都没有削减,我们得出真实。请注意,这不是经典逻辑中的否定,并且它受到切割的非逻辑效应的影响。假设您将谓词land/1定义为大陆之一:

    land(africa).
    land(america).
    land(antarctica).
    land(asia).
    land(australia).
    land(europe).
    

    然后将水定义为不在陆地上的所有东西:

    water(X) :-
      neg(land(X)).
    

    然后你可以正确获得:

    ?- water(pacific).
    true.
    
    ?- water(africa).
    false.
    

    但你也可以得出:

    ?- water(space).
    true.
    

    哪个不应该成立。特别是在经典逻辑中:

    land(africa) ∧
    land(america) ∧
    land(antarctica) ∧
    land(asia) ∧
    land(australia) ∧
    land(europe) → ¬ land(space).
    

    无效。同样,如果你在Prolog中使用否定,你应该清楚自己在做什么。

答案 2 :(得分:3)

以下是我尝试使用if_/3

counter([], []).
counter([H|T], [[H,C]|OutT] ):-
         if_( 
               T=[], 
               (C = 1,OutT=[]), 
               (
                 [H|T] = [H,H1|T2],
                 if_(
                       H=H1, 
                       (counter([H1|T2], [[H1,C1]|OutT]), C is C1+1),
                       (C = 1, counter([H1|T2], OutT))
                     )
               )  
            ).