Prolog 中的协程:当参数是列表时(它具有固定长度)

Coroutining in Prolog: when argument is a list (it has fixed length)

问题

是否可以安排一个目标在列表的长度已知/固定后立即执行,或者正如@false 在评论中指出的那样,给定的参数成为一个[正确的] 列表?沿着这条线:

when(fixed_length(L), ... some goal ...).

When-conditions 可以仅使用 ?=/2nonvar/1ground/1,/2;/2 构造,但似乎它们不是很查看整个列表时很有用。

作为进一步的细节,我正在寻找一种解决方案 如果可能的话。

动机

我认为当有人想使用谓词 p(L) 来检查列表 L 的 属性 但不以生成方式使用它时,这个条件可能很有用。

例如如果 L 具有固定长度(即 L 是一个列表),可能 [出于效率或终止原因] 人们更愿意按此顺序执行以下连词 p1(L), p2(L),并以相反的顺序 p2(L), p1(L) 否则(如果 L 是部分列表)。

这可能是这样实现的:

when(fixed_length(L), p1(L)), p2(L).

更新

我确实实现了一个,但它缺乏纯度。

我已经设法回答了我自己的问题,但不是一个纯粹的解决方案。

一些观察

当列表的长度准确已知时,编写计划执行某个目标的程序时遇到的困难是实际情况可能会发生变化。考虑一下:

when(fixed_length(L), Goal)

如果 L 未绑定或如果 最后一个尾部 未绑定,列表的长度可能会改变。假设我们有这个参数 L = [_,_|Tail]L 仅当 Tail 具有固定宽度时才具有固定宽度(换句话说,如果 T 是列表,则 L 是列表)。因此,检查 Tail 的条件可能是一开始唯一要做的事情。但是,如果 Tail 变为 [a|Tail2],则需要一个新的 when-condition 来测试 Tail2 是否是一个列表。

解决方法

1.获取 when-condition

我已经实现了一个谓词,它将部分列表与 when-condition 相关联,when-condition 表示它何时可能成为列表(即 nonvar(T) 其中 T 最深的尾).

condition_fixed_length(List, Cond):-
    \+ (List = []),
    \+ \+ (List = [_|_]),
    List = [_|Tail],
    condition_fixed_length(Tail, Cond).
condition_fixed_length(List, Cond):-
    \+ \+ (List = []),
    \+ \+ (List = [_|_]),
    Cond = nonvar(List).

2。递归 when-conditioning

check_on_fixed_length(List, Goal):-
    (
         condition_fixed_length(List, Condition)
     ->
         when(Condition, check_on_fixed_length(List, Goal))
     ;
         call(Goal)
    ).

示例查询

假设我们要检查当L的大小固定时L的所有元素都是a

?- check_on_fixed_length(L, maplist(=(a), L)).
when(nonvar(L), check_on_fixed_length(L, maplist(=(a), L))).

... 然后 L = [_,_|Tail]:

?- check_on_fixed_length(L, maplist(=(a), L)), L = [_,_|L1].
L = [_G2887, _G2890|L1],
when(nonvar(L1), check_on_fixed_length([_G2887, _G2890|L1], maplist(=(a), [_G2887, _G2890|L1]))).

?- check_on_fixed_length(L, maplist(=(a), L)), L = [_,_|L1], length(L1, 3).
L = [a, a, a, a, a],
L1 = [a, a, a].

杂质

conditon_fixed_length/2是杂质的来源,从下面的查询可以看出:

?- L = [X, Y|Tail], condition_fixed_length(L, Cond), L = [a,a].
L = [a, a],
X = Y, Y = a,
Tail = [],
Cond = nonvar([]).

?- L = [X, Y|Tail], L = [a, a], condition_fixed_length(L, Cond).
false.

如果 when/2 支持条件 list/1 就好了。与此同时,请考虑:

list_ltruth(L, Bool) :-
   freeze(L, nvlist_ltruth(L, Bool)).

nvlist_ltruth(Xs0, Bool) :-
   (  Xs0 == [] -> Bool = true
   ;  Xs0 = [_|Xs1] -> freeze(Xs1, nvist_ltruth(Xs1, Bool))
   ;  Bool = false
   ).

when_list(L, Goal_0) :-
   nvlist_ltruth(L, Bool),
   when(nonvar(Bool),( Bool == true, Goal_0 )).

因此您也可以将其与其他条件相结合。

如果 L 不是列表,可能会产生类型错误。

   when(nonvar(Bool), ( Bool == true -> Goal_0 ; sort([], L) ).

以上技巧仅适用于符合 ISO 的 Prolog 系统,如 SICStus 或 GNU,为 sort([],[a|nonlist]) 生成 type_error(list,[a|nonlist]),否则将其替换为:

   when(nonvar(Bool),
      ( Bool == true -> Goal_0 ; throw(error(type_error(list,L), _)).

许多系统包含一些特定于实现的内置功能,例如 '$skip_list' 以快速遍历列表,您可能想在这里使用它。