Prolog 中的功能模式

Functional patterns in Prolog

如何创建一个带有另一个谓词和 returns 它的派生版本的谓词?

例如,成对谓词可以相当机械地扩展以应用于列表:

all_whatever(_, []).
all_whatever(X, [Y|T]) :- 
    whatever(X, Y), 
    all_whatever(X, T).

的定义是什么
pairwise_listwise(whatever, all_whatever).

如果不是 possible/common/clunky/violates 原则,替代模式是什么?

有两种不同的方法可以实现您想要的。最简单且可能是首选的方法是定义一个元谓词,它接受任何二元谓词并将其应用于列表的所有元素,如下所示:

listwise(_,_,[]).
listwise(P,Y,[X|Xs]) :-
    call(P,Y,X),
    listwise(P,Y,Xs).

然后您可以将其称为 listwise(whatever, Y1, Xs1) 以将 whatever 应用于 Y1 以及 Xs1 的每个元素。

这要归功于 call/N 元谓词。请注意,此元谓词也可以将部分构造的目标作为第一个参数,因此替代公式可以是:

listwise(_,[]).
listwise(P,[X|Xs]) :-
    call(P,X),
    listwise(P,Xs).

然后称为listwise(whatever(Y1),Xs1)。这个版本的谓词实际上被称为 maplist/2 而不是 listwise,至少在 SWI-Prolog(在模块 library(apply) 中)和 SICStus Prolog(在模块 library(lists) 中)是这样。

实现您想要的(实际上更接近您所要求的)的第二种方法是使用术语扩展实际定义一个新谓词 all_whatever/2。术语扩展是一种在加载术语时重写术语的机制(有关 SWI-Prolog 中的更多详细信息,请参见例如:https://www.swi-prolog.org/pldoc/doc_for?object=term_expansion/2)。我在这里展示的是 SWI-Prolog 版本,它通过为 term_expansion/2 谓词定义一个子句来实现。此机制在不同系统中的工作方式不同或完全缺失。

term_expansion(pairwise_listwise(PairPred,ListPred), ExpandedTerm) :-
    TerminalCall =.. [ListPred,_,[]],
    RecursiveCall =.. [ListPred,Y,[X|Xs]],
    SingleCall =.. [PairPred,Y,X],
    FinalCall =.. [ListPred,Y,Xs],
    ExpandedTerm = [TerminalCall, (RecursiveCall :- (SingleCall, FinalCall))].

在这个子句中,ExpandedTerm 是一个列表,定义了我们要定义的两个子句,其中的所有术语都是使用 =.. 从谓词名称构建的。然后可以如下定义新谓词:

pairwise_listwise(whatever, all_whatever).

加载此代码时,该子句将被扩展并替换为定义新谓词的两个子句 all_whatever。现在可以调用 all_whatever(Y1,Xs1).

我更喜欢第一种方法(概念上更简单并且适用于 Prolog 版本)但我认为了解术语扩展机制的存在也很有用。