如何创建一个接受另一个谓词并返回它的派生版本的谓词?
例如,成对谓词可以相当机械地扩展以应用于列表:
all_whatever(_, []).
all_whatever(X, [Y|T]) :-
whatever(X, Y),
all_whatever(X, T).
的定义是什么
pairwise_listwise(whatever, all_whatever).
如果不可能/常见/笨拙/违反原则,那么替代模式是什么?
如何创建一个接受另一个谓词并返回它的派生版本的谓词?
例如,成对谓词可以相当机械地扩展以应用于列表:
all_whatever(_, []).
all_whatever(X, [Y|T]) :-
whatever(X, Y),
all_whatever(X, T).
的定义是什么
pairwise_listwise(whatever, all_whatever).
如果不可能/常见/笨拙/违反原则,那么替代模式是什么?
有两种不同的方法可以实现您想要的。最简单且可能首选的方法是定义一个元谓词,它接受任何二元谓词并将其应用于列表的所有元素,如下所示:
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).
加载此代码时,该子句将被扩展并替换为定义新 predicate 的两个子句all_whatever
。现在可以调用例如all_whatever(Y1,Xs1)
。
我更喜欢第一种方法(概念上更简单,并且适用于 Prolog 版本),但我认为了解术语扩展机制的存在也很有用。