首页 > 解决方案 > 了解 Prolog 的副作用,例如 write/1

问题描述

我目前正在学习 Prolog,我很难理解副作用。

我有一个练习来编写一个谓词,该谓词将一些字符串写入 N 次。给定的解决方案如下所示:

n_times(N) :- 1 =< N.
n_times(N) :- N > 1, N1 is N - 1, n_times(N1).
test_x(N) :- n_times(N), write('x'), fail.
test_x(_).

有人可以解释为什么这有效吗?为什么要write('x')执行N次?据我了解Prolog它应该尝试找到一个解决方案n_times(N)然后执行write('x')一次。我想这与副作用有关,但我找不到实际的解释。

顺便说一下,我自己的解决方案如下所示:

test_x(N) :- write('x'), N1 is N - 1, N1 >= 1, test_x(N1).

在这里,我可以看到write每次递归调用都会调用它。

标签: prolog

解决方案


这就是所谓的失败驱动循环

一个更简单的情况是

repeat :- true.
repeat :- repeat.

forever_x :- repeat, write('x'), fail.

永远x在提示符下打印。

为什么?因为 Prolog 的目标连词 ( ,, "and") 就像嵌套循环

find(G):- this(X1), that(X2).

就像(在伪代码中)

def find(G):
         foreach solution X1 to { this(X1) }:
             foreach solution X2 to { that(X2) }:
                 yield G using the found values X1, X2.

回溯自然发生在循环中。如果对于某些X1没有X2满足that(X2),则产生 noG,并且外部循环只是跳到满足的下一个X1this(X1)

Prolog 的;目标分离( ,“或”)只是循环的并置(只是将一个循环放在另一个循环)。

因此,repeat行为的定义好像由

def repeat:
     yield        % yield an empty value that isn't used anywhere
     repeat       % call self, yielding again; and again; repeating endlessly

def forever_x:
     foreach solution to { repeat }:           % endless stream of empty solutions
         foreach solution to { write('x') }:   % there will be only one, empty solution
            foreach solution to { fail }:      % there will be no solutions, ever, so
                yield                          % this will never happen

和你的n_times/1,好像

% n_times(N) :- N =< 1.
% n_times(N) :- N > 1, N1 is N - 1, n_times(N1).

def n_times(n):
    foreach solution to { n =< 1 }:            % succeeds at most once
         yield n
    foreach solution to { n > 1 }:             % at most once, mutually exclusively
         foreach solution to { n1 = n - 1 }:   % there will be only one solution
             n_times(n1)

所以很自然这会成功,即“屈服”,n次。


推荐阅读