14

所以univ运算符。我不太明白。

例如这个:

foo(PredList,[H|_]) :- bar(PredList,H).
foo(PredList,[_|T]) :- foo(PredList,T),!.

bar([H|_],Item) :- G =.. [H,Item],G.
bar([_|T],Item) :- bar(T,Item).

这是在做什么?这看起来看看另一个谓词是否为真。我不明白“..”是做什么的。

如果没有 univ 运算符,你将如何重写它?

4

2 回答 2

17

Univ ( =..) 将一个术语分解为一个成分列表,或者从这样的列表中构造一个术语。尝试:

?- f(x,y) =.. L.
L = [f, x, y].

?- f(x,y,z) =.. [f|Args].
Args = [x, y, z].

?- Term =.. [g,x,y].
Term = g(x, y).

bar似乎将每个谓词称为PredListon Item,并foo在 s 上回溯Item。(使用变量作为谓词是不可移植的;call应该首选谓词。)

编辑: Kaarel 是对的,univ 可以替换为functor/3and arg/3,如下:

bar([H|_],Item) :-
    functor(Goal,H,1),   % unifies Goal with H(_)
    arg(1,Goal,Item),    % unifies first argument of Goal with Item
    call(Goal).          % use this for portability
于 2010-11-09T08:18:32.173 回答
3

我认为最合适的重写是:

 bar( [H|_], Item ) :- call(H, Item).

call/n尚未成为 ISO 核心标准的一部分,但它们可能会在不久的将来成为 (*)。许多 Prolog 系统已经支持它们。

call/n应该优先于简单(=..)/2functor/3+解决方案的原因之一arg/3。该call/n解决方案能够处理闭包(**)。

使用简单的(=..)/2functor/3+arg/3解决方案,bar/2只能使用第一个列表参数中的原子调用。例如:

 p1(1).
 p2(2).
 ?- bar( [p1, p2], 1 ).
 Yes
 ?- bar( [p1, p2], 2 ).
 Yes
 ?- bar( [p1, p2], 3 ).
 No

使用闭包,我们不限于原子,我们可能会节省一些编码工作。例如我们可以直接执行以下操作:

 ?- bar( [=(1), =(2)], 1 ).
 Yes
 ?- bar( [=(1), =(2)], 2 ).
 Yes
 ?- bar( [=(1), =(2)], 3 ).
 No

最好的祝福

(*)
技术勘误草案 2
http://www.complang.tuwien.ac.at/ulrich/iso-prolog/dtc2#call

(**)
谁发明了它?:call/n谓词
http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/naish.html

于 2011-12-14T11:43:41.450 回答