在Prolog中插入一个剪切以使关系子句绑定但是双向

Jse*_*mol 4 prolog prolog-cut

考虑以下Prolog程序:

transform([], []).
transform([X | Xs],[Y | Ys]):-
    isSpecial(X),
    isSpecial(Y),
    transformSpecial(X,Y),
    transform(Xs,Ys).
transform([X | Xs],[ X | Ys]):-
    transform(Xs,Ys).

isSpecial(foo).
isSpecial(bar).
isSpecial(foobar).

transformSpecial(X,Y):-
    isSpecial(X),
    isSpecial(Y),
    not(X = Y).
Run Code Online (Sandbox Code Playgroud)

有些情况下我会打电话tranform([foo, 1, 2], X)和我想打电话的情况transform(X, [foo, 1, 2]).

在这两种情况下,我都希望X与之[bar, 1, 2]结合[foobar, 1, 2],但不与之结合[foo, 1, 2].也就是说,我希望一旦谓词正确识别出第二个子句适用,它就应该只使用第二个子句来回溯.

我应该在哪里插入切口以实现此行为?

fal*_*lse 5

你的程序目前太笼统了.毕竟,您的查询有三种解决方案,但只有第一种解决方案.最后一个是错的.

?- transform([foo, 1, 2], Xs).
   Xs = [bar, 1, 2]
;  Xs = [foobar, 1, 2]
;  Xs = [foo, 1, 2].   % wrong
Run Code Online (Sandbox Code Playgroud)

削减现在可能会减少解决方案的数量.但大部分时间这都是非常错误的.您的问题应该"插入切口以实现此行为?" 只有答案:没有地方.你需要做更多的事情来实现这一目标.

从本质上讲,您所描述的是元素转换.所以也许我们坚持一次描述一个元素.

el_transformed(X, Y) :-
    isSpecial(X),
    isSpecial(Y),
    dif(X,Y).
el_transformed(X, X).   % too general!
Run Code Online (Sandbox Code Playgroud)

maplist(el_transformed, [foo, 1, 2], Xs)像以前一样使用......

请注意,此版本与原始代码一样错误.但现在,添加额外条件很简单:

el_transformed(X, Y) :-
   isSpecial(X),
   isSpecial(Y),
   dif(X,Y).
el_transformed(X, X) :-
   dif(X, foo),
   dif(X, bar),
   dif(X, foobar).
Run Code Online (Sandbox Code Playgroud)

有一个很大的缺点:对于某些情况,这个版本不是很确定:

?- el_transformed(foobar, bar).
   true
;  false.
Run Code Online (Sandbox Code Playgroud)

如果您想从中获得更多,请考虑使用SICStusSWIlibrary(reif)两者 .

el_transformed(X, Y) :-
   if_(( ( X = foo ; X = bar ; X = foobar ),
         ( Y = foo ; Y = bar ; Y = foobar ) ),
       dif(X,Y),
       X = Y).
Run Code Online (Sandbox Code Playgroud)

有了这个表述,我们不需要重复自己.要检查,如果代码没问题,让我们尝试最常见的查询:

?- el_transformed(X, Y).
   X = foo, Y = bar
;  X = foo, Y = foobar
;  X = bar, Y = foo
;  X = bar, Y = foobar
;  X = foobar, Y = foo
;  X = foobar, Y = bar
;  X = Y, dif(Y,foobar), dif(Y,bar), dif(Y,foo).
Run Code Online (Sandbox Code Playgroud)

您正在寻找可能发生的所有可能情况!没有其他案例需要考虑.

因此,作为经验法则:每当您想要一个"双向"工作的谓词时,请考虑将其写为"全向"!


也许你不喜欢明确提到X = foo ; X = bar ; X = foobar,在这种情况下,我们将不得不深入挖掘,通过以下isSpecial/1方式isSpecial_t/2:

isSpecial_t(X, T) :-
   call(
      ( X = foo
      ; X = bar
      ; X = foobar
      ), T).

el_transformed(X, Y) :-
   if_( ( isSpecial_t(X), isSpecial_t(Y) ), dif(X, Y) , X = Y ).
Run Code Online (Sandbox Code Playgroud)