删除列表中的前导 s(s(0))

问题描述 投票:0回答:2

(这是那个问题的后续)。

如何写

lead1(Xs,Ys)
这是正确的,当且仅当
Ys
Xs
的后缀,删除了所有前导
s(s(0))
项。因此,现在的问题不是删除前导
0
,而是删除前导
s(s(0))

与原来的问题相比,难点在于如何正确处理

s(X)
s(s(X))
的情况。

prolog prolog-coroutining
2个回答
5
投票

这是带有 if_/3=/3 的版本:

list_suffix([],[]).
list_suffix([X|Xs],S) :-
   if_(X=s(s(0)), list_suffix(Xs,S), S=[X|Xs]).

具有ground-first参数的查询确定性地成功:

?- list_suffix([s(0)],S).
S = [s(0)].

?- list_suffix([s(0),s(s(0))],S).
S = [s(0), s(s(0))].

?- list_suffix([s(s(0)),s(0),s(s(0))],S).
S = [s(0), s(s(0))].

?- list_suffix([s(s(0)), s(s(0)),s(0),s(s(0))],S).
S = [s(0), s(s(0))].

如果列表包含与 s/1 不同的术语,则说

f(_)
第二个列表与第一个列表相同:

?- list_suffix([f(_)],S).
S = [f(_G201)].

?- list_suffix([f(_)],[]).
false.

部分实例化的列表也可以工作:

?- list_suffix([X, s(s(0)),s(0),s(s(0))],S).
X = s(s(0)),
S = [s(0), s(s(0))] ;
S = [X, s(s(0)), s(0), s(s(0))],
dif(X, s(s(0))).

最通用的查询也有效,但以不公平的方式列出答案:

?- list_suffix(X,Y).
X = Y, Y = [] ;
X = [s(s(0))],
Y = [] ;
X = [s(s(0)), s(s(0))],
Y = [] ;
X = [s(s(0)), s(s(0)), s(s(0))],
Y = [] ;
.
.
.

但是,这可以通过前缀目标长度/2来解决:

?- length(X,_), list_suffix(X,Y).
X = Y, Y = [] ;
X = [s(s(0))],
Y = [] ;
X = Y, Y = [_G155],
dif(_G155, s(s(0))) ;
X = [s(s(0)), s(s(0))],
Y = [] ;
X = [s(s(0)), _G79],
Y = [_G79],
dif(_G79, s(s(0))) ;
X = Y, Y = [_G155, _G158],
dif(_G155, s(s(0))) ;
X = [s(s(0)), s(s(0)), s(s(0))],
Y = [] ;
.
.
.

2
投票

Hiere 是我对上一个问题的回答的改编。它显示了使用when/2而不是freeze/2。 freeze/2 仅遵循第一个参数的 nonvar/1 条件。 when/2 可以遵循更复杂的条件。

lead(X, Y) :- var(X), !, freeze(X, lead(X,Y)).
lead([X|Y], Z) :- \+ ground(X), !, when(ground(X), lead([X|Y],Z)).
lead([s(s(0))|X], Y) :- !, lead(X, Y).
lead(X, X).

这里有一些示例运行,我选择了与我对上一个答案给出的答案类似的示例。我们看到当列表参数逐渐实例化时,when/2 如何适应自己的条件:

?- lead([s(0),s(s(0)),s(s(0)),s(0)],Y).
Y = [s(0), s(s(0)), s(s(0)), s(0)].

?- lead([s(s(0)),s(s(0)),s(s(0)),s(0)],Y).
Y = [s(0)].

?- lead([X,s(s(0)),s(s(0)),s(0)],Y), X=s(_).
X = s(_G3686),
when(ground(_G3686), lead([s(_G3686), s(s(0)), s(s(0)), s(0)], Y)).

?- lead([X,s(s(0)),s(s(0)),s(0)],Y), X=s(0).
X = s(0),
Y = [s(0), s(s(0)), s(s(0)), s(0)].

?- lead([X,s(s(0)),s(s(0)),s(0)],Y), X=s(s(_)).
X = s(s(_G3713)),
when(ground(_G3713), lead([s(s(_G3713)), s(s(0)), s(s(0)), s(0)], Y)).

?- lead([X,s(s(0)),s(s(0)),s(0)],Y), X=s(s(0)).
X = s(s(0)),
Y = [s(0)].

freeze/2 和when/2 是协程原语。它们的纯洁性在文献中有详细记载。根据这个来源,第一个具有协同路由的 Prolog 系统是带有 geler/2 原语的 Prolog-II。消息来源还提到了协同路由对引导约束求解器的重要性。

假设纯度通过交换性进行测试,这是一个示例测试:

?- lead([X,s(s(0)),s(s(0)),s(0)],Y), X=s(s(0)).
X = s(s(0)),
Y = [s(0)].

?- X=s(s(0)), lead([X,s(s(0)),s(s(0)),s(0)],Y).
X = s(s(0)),
Y = [s(0)].

但是 freeze/2 和 when/2 不一定保证完整性,正如我在第一个答案中已经写的那样,我们可能需要“最后”做一些事情。意味着在查询之后我们可能会有一组陷入困境的目标。在约束规划中,我们将开始标记。

freeze/2 和when/2 也无法通过组合目标来发现早期失败,正如约束求解器可以做到的那样。

上面的示例使用 SWI-Prolog 运行,无需导入,并且在 Jekejeke Prolog 中使用 Minlog 扩展和导入库(term/suspend)。

© www.soinside.com 2019 - 2024. All rights reserved.