(序言)我可以抽象化此模式的所有排列,而不必分别编写每个吗?

时间:2019-07-18 14:31:53

标签: prolog

我只是从序言开始,尽管我认为我已经对如何使用它有了很好的了解,但我在这里遇到了麻烦。我有这样的规则:

foo(A, B, C) :- bar(A, B), baz(C).
foo(A, B, C) :- bar(A, C), baz(B).
foo(A, B, C) :- bar(B, A), baz(C).
% etc, etc, for all permutations of `A, B, C`

但是,真正的规则有3个以上的参数,将它们全部写出/生成它们将使我最终得到一个非常大的文件。有没有办法抽象这种模式?

2 个答案:

答案 0 :(得分:4)

这就是我要做的:

@Library('name_of_repo')
import name.of.package.* 
utils = new name_of_pipeline()
// here you can invoke
utils.myFunc(var)

这样的想法是,我们将使用select/3(我最喜欢的谓词之一)重新组合这些参数的每种组合,然后对它们进行置换,我们就可以移交给您关心的两个谓词。

这样做可能更清楚,但是L2总是包含一个元素,因此我在上面的上一个子句中将其匹配:

foo(A, B, C) :- 
    select(X, [A, B, C], L1),
    select(Y, L1, [Z]),
    bar(X, Y),
    baz(Z).

编辑:让我们处理任意N个。首先,我们需要一个foo(A, B, C) :- select(X, [A, B, C], L1), select(Y, L1, L2), select(Z, L2, _), bar(X, Y), baz(Z). ,该列表为我提供了N个项目。我将使用DCG编写此文件,因为它对我来说更容易:

select_n/4

DCG不仅是解析文本的好方法,而且还是将具有输入列表和输出列表的谓词串在一起的便捷方法。

现在,我们可以使用此帮助程序来构建您的谓词的更一般的版本。假设您为简单起见列出了一个列表:

select_n([X|Xs], N) --> select(X), { succ(N0, N) }, select_n(Xs, N0).
select_n([], 0) --> [].

您可以用您想要的任何内容替换上面的foo(L) :- select_n(BarArgs, 2, L, L1), select_n(BazArgs, 1, L1, []), apply(bar, BarArgs), apply(baz, BazArgs). 2,大概是基于您要调用的1bar的组合。< / p>

如果您不使用SWI,或者只想使用baz,则必须在使用call/1之前使用univ运算符=..来构建术语:< / p>

call/1

答案 1 :(得分:1)

另一个答案已经很好。只是一些进一步的想法。

在Prolog中,为您的微语言编写小型解释器非常容易。这是解决原始问题的另一种(廉价)方法:

foo(A, B, C) :-
    permutation([A, B, C], [X, Y, Z]),
    bar(X, Y), baz(Z).

...并使用call,您可以参数化barbaz

foo(Bar, Baz, A, B, C) :-
    permutation([A, B, C], [X, Y, Z]),
    call(Bar, X, Y), call(Baz, Z).

这意味着您现在可以(按名称)传递Arity 2为Bar的任何谓词以及Arity 1为Baz的任何谓词。而且,如果您有一个接受3个参数的谓词bar_x,则可以尽早绑定第一个参数。例如,您可以将foo/5称为:

?- foo(bar(hello), baz, 1, 2, 3).

这将为第一个解决方案评估bar(hello, 1, 2)

因此,现在唯一不平凡的问题是,您的界面是什么?您想如何写下您的查询?您是将这三个参数作为单独的参数还是作为列表提供?您是否希望参数化谓词?依此类推。