我有一个包含整数和匿名变量的列表,我试图找到一个特殊值的索引。问题是一旦我nth1/3
用来查找索引 Prolog 将值分配给匿名变量,因此我也找到了索引。
示例:
List = [1,\_,1]
,我想要的结果X = 1, X = 3
来自nth1(X,List,1)
,但正如我得到之前所述X = 1, X = 2, X = 3
。
我有一个包含整数和匿名变量的列表,我试图找到一个特殊值的索引。问题是一旦我nth1/3
用来查找索引 Prolog 将值分配给匿名变量,因此我也找到了索引。
示例:
List = [1,\_,1]
,我想要的结果X = 1, X = 3
来自nth1(X,List,1)
,但正如我得到之前所述X = 1, X = 2, X = 3
。
您的需求中隐藏了一个有点问题的问题:它们违反了一个重要的声明性属性,称为单调性。我们的意思是添加约束最多可以使解决方案更具体,而不是更通用。
例如,使用您发布的解决方案,我们得到:
?- list_el_index([_], 1, N)。 错误的。
现在我通过对迄今为止免费的匿名变量施加额外的要求来添加约束:
?- Var = 1 , list_el_index([ Var ], 1, N)。 变量 = 1, N = 0。
我的意思是:来吧!我们添加了一个约束,因此得到了比以前更多的解决方案?这样的结果是不幸的,并阻止我们以合乎逻辑的 方式对该程序进行推理。
该计划在其他方面也令我们失望。例如,让我们问:到底有哪些解决方案?
?- list_el_index(Ls, El, I)。 不终止
理想情况下,我们希望程序在这种情况下生成解决方案!这种普遍性是逻辑编程最吸引人的地方之一,并将其与更底层的范式区分开来。
解决此类问题的一种方法是用符号区分出现在列表中的不同类型的元素。
例如,让我们使用:
u
为未知值。i(I)
对于一个整数 I
。使用这种新表示,您的解决方案将变为:
list_el_index([i(I)|_], I, 0)。 list_el_index([_|Tail], 元素, 索引) :- list_el_index(尾巴,元素,索引0), 索引 #= 索引 0+1。
我还冒昧地替换(is)/2
为(#=)/2
,宣传并坚持更通用的整数运算,如果需要,我们可以更自由地重新排序目标。根据您的 Prolog 实现,您可能必须导入一个库才能从 (#=)/2
.
使用这种表示,您的初始情况变为:
?- list_el_index([i(1), u ,i(1)], 1, 索引)。 索引 = 0 ; 索引 = 2 ; 错误的。
这可以按需要工作!
重要的是,我们也可以更一般地使用谓词,即生成可能的答案:
?- list_el_index(Ls, El, I)。 Ls = [i(El)|_2994], 我 = 0 ; Ls = [_2992, i(El)|_3000], 我 = 1 ; Ls = [_2992, _2998, i(El)|_3006], 我 = 2 ; Ls = [_2992, _2998, _3004, i(El)|_3012], 我 = 3。
由于程序的单调性,我们可以通过迭代深化来公平地枚举解:
?-长度(Ls,_),list_el_index(Ls,El,I)。 Ls = [i(El)], 我 = 0 ; Ls = [i(El), _4812], 我 = 0 ; Ls = [_4806, i(El)], 我 = 1 ; Ls = [i(El), _4812, _4818], 我 = 0 ; 等等
通过使用让我们通过模式匹配来区分情况的表示,这已经成为可能。考虑使用这种方法使您的程序在所有方向上都可用,并使逻辑推理适用。通过使用适当的包装器或常量很容易应用,并且大大增加了程序的通用性。
这有效:
- 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.
感谢潜伏者的提示,我想出了这个解决方案。
list_el_index([El1|_], El2, 0) :-
El1 == El2.
list_el_index([_|Tail], Element, Index) :-
list_el_index(Tail, Element, Index1),
Index is Index1+1.