序言是否有 spread/splat/*args 运算符?

Does prolog have a spread/splat/*args operator?

在许多过程语言中 (例如 python),我可以 "unpack" 一个列表并将其用作函数的参数。例如...

def print_sum(a, b, c):
  sum = a + b + c
  print("The sum is %d" % sum)

print_sum(*[5, 2, 1])

此代码将打印:“The sum is 8

这里是 documentation for this language feature.

序言是否有类似的功能?

有没有办法在 Prolog 中复制这种 argument-unpacking 行为?

例如,我想在将列表变量传递给 call 之前解压它。

我可以写这样的谓词吗?

assert_true(Predicate, with_args([Input])) :-
  call(Predicate, Input).

% Where `Input` is somehow unpacked before being passed into `call`.

...然后我可以用

查询
?- assert_true(reverse, with_args([ [1, 2, 3], [3, 2, 1] ])).
% Should be true, currently fails.

?- assert_true(succ, with_args([ 2, 3 ]).
% Should be true, currently fails.

?- assert_true(succ, with_args([ 2, 4 ]).
% Should be false, currently fails.

备注

内置的 (=..)/2 (univ) 就是为了这个目的。例如

?- G =.. [g, 1, 2, 3].
G = g(1,2,3).

?- g(1,2,3) =.. Xs.
Xs = [g,1,2,3].

但是,请注意,(=..)/2 的许多用法(其中参数数量是固定的)可以替换为 call/2...call/8.

首先:如果您知道列表的形状,使用统一和模式匹配来获取列表的元素或任何项的参数太容易了。换句话说:

sum_of_three(X, Y, Z, Sum) :- Sum is X+Y+Z.

?- List = [5, 2, 1],
   List = [X, Y, Z], % or List = [X, Y, Z|_] if the list might be longer
   sum_of_three(X, Y, Z, Sum).

例如,如果您有命令行参数,并且您只对前两个命令行参数感兴趣,那么很容易像这样得到它们:

current_prolog_flag(argv, [First, Second|_])

许多标准谓词将列表作为参数。例如,任何需要多个选项的谓词,如 open/3open/4。这样的一对可以实现如下:

open(SrcDest, Mode, Stream) :-
    open(SrcDest, Mode, Stream, []).

open(SrcDest, Mode, Stream, Options) :-
    % get the relevant options and open the file

这里可以使用像library(option)这样的库来获取相关选项,例如可以这样使用:

?- option(bar(X), [foo(1), bar(2), baz(3)]).
X = 2.

这就是传递命名参数的方法。

中没有提到的另一件事:在 Prolog 中,您可以这样做:

Goal = reverse(X, Y), X = [a,b,c], Y = [c,b,a]

稍后:

call(Goal)

甚至

Goal

换句话说,我不认为将参数作为列表传递而不是将目标作为术语传递有什么意义。参数在什么时候是列表,为什么将它们打包到列表中?

换句话说:考虑到 call 的工作原理,通常不需要将列表 [X, Y, Z] 解包为连词 X, Y, Z,然后您可以将其用作参数列表.正如对你的问题的评论,这些都很好:

call(reverse, [a,b,c], [c,b,a])

call(reverse([a,b,c]), [c,b,a])

call(reverse([a,b,c], [c,b,a]))

最后一个同

Goal = reverse([a,b,c], [c,b,a]), Goal

这就是为什么你可以这样做:

?- maplist(=(X), [Y, Z]).
X = Y, Y = Z.

而不是写:

?- maplist(=, [X,X], [Y, Z]).
X = Y, Y = Z.