Prolog nth1 匿名变量

Prolog nth1 anonymous variables

我有一个包含整数和匿名变量的列表,我试图找到一个特殊值的索引。问题是我使用 nth1/3 来查找索引 Prolog 将值分配给匿名变量,因此我也找到了索引。

示例: List = [1,\_,1],我想要 nth1(X,List,1) 的结果 X = 1, X = 3,但如前所述,我得到 X = 1, X = 2, X = 3

这个有效:

 - L = [1,_,1], nth1(X, L, Y), ground(Y), Y= 1.
L = [1,_310914,1],
X = Y, Y = 1 ;
L = [1,_310914,1],
X = 3,
Y = 1.

感谢 lurkers 的提示,我想出了这个解决方案。

list_el_index([El1|_], El2, 0) :-
    El1 == El2.
list_el_index([_|Tail], Element, Index) :-
    list_el_index(Tail, Element, Index1),
    Index is Index1+1.

您的要求中隐藏了一个有点问题的问题:它们违反了 一个重要的声明属性,称为单调性。我们的意思是,添加 约束至多可以使解决方案更具体,而不会更笼统。

例如,根据您发布的解决方案,我们得到:

?- list_el_index([_], 1, N).
false.

现在我添加一个约束,对迄今为止免费的匿名变量施加额外的要求:

?- Var = 1, list_el_index([Var], 1, N).
Var = 1,
N = 0 .

我的意思是:加油!我们添加了一个约束,结果得到比以前更多的解决方案?这样的结果是不幸的,并且阻止我们以合乎逻辑的方式对这个程序进行推理。

该程序在其他方面也让我们失望。例如,让我们问:到底有哪些解决方案?

?- list_el_index(Ls, El, I).
nontermination

理想情况下,我们希望程序在这种情况下生成 解决方案!这种普遍性是逻辑编程最吸引人的地方之一,并将其​​与更多低级范例区分开来。


解决此类问题的一种方法是象征性地区分列表中出现的不同种类元素。

例如,让我们使用:

  • u 未知 值。
  • i(I) 对于 整数 I.

有了这个新表示,您的解决方案就变成了:

list_el_index([i(I)|_], I, 0).
list_el_index([_|Tail], Element, Index) :-
    list_el_index(Tail, Element, Index0),
    Index #= Index0+1.

我还冒昧地将 (is)/2 替换为 (#=)/2,以宣传并坚持使用更通用的整数算法,以便我们在必要时更自由地重新排序目标。根据您的 Prolog 实施,您可能必须导入一个库才能受益于 (#=)/2

通过这种表示,您的初始情况变为:

?- list_el_index([i(1),u,i(1)], 1, Index).
Index = 0 ;
Index = 2 ;
false.

这符合预期!

重要的是,我们还可以更一般地使用谓词,即生成个可能的答案:

?- list_el_index(Ls, El, I).
Ls = [i(El)|_2994],
I = 0 ;
Ls = [_2992, i(El)|_3000],
I = 1 ;
Ls = [_2992, _2998, i(El)|_3006],
I = 2 ;
Ls = [_2992, _2998, _3004, i(El)|_3012],
I = 3 .

由于程序的单调性,我们可以公平地通过迭代加深枚举解决方案:

?- length(Ls, _), list_el_index(Ls, El, I).
Ls = [i(El)],
I = 0 ;
Ls = [i(El), _4812],
I = 0 ;
Ls = [_4806, i(El)],
I = 1 ;
Ls = [i(El), _4812, _4818],
I = 0 ;
etc.

这已经成为可能,因为我们使用了一种表示法,让我们可以通过模式匹配 来区分案例。考虑使用这种方法使您的程序在各个方向都可用,并使逻辑推理适用。通过使用适当的包装器或常量应用起来非常容易,并且大大增加了程序的通用性。