微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Prolog 中的功能模式

如何解决Prolog 中的功能模式

如何创建一个采用另一个谓词并返回它的派生版本的谓词?

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

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,X),listwise(P,Xs).

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

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

listwise(_,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,[X|Xs]],SingleCall =.. [PairPred,X],FinalCall =.. [ListPred,Xs],ExpandedTerm = [TerminalCall,(RecursiveCall :- (SingleCall,FinalCall))].

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

pairwise_listwise(whatever,all_whatever).

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

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。