【问题标题】:PROLOG List filter predicate not aswering true or falsePROLOG 列表过滤谓词不区分真假
【发布时间】:2013-05-10 23:29:10
【问题描述】:

我正在尝试创建一个谓词,它接受两个向量/列表并使用第一个作为过滤器。例如:

?- L1=[0,3,0,5,0,0,0,0],L2=[1,2,3,4,5,6,7,8],filter(L1,L2,1).
   L1 = [0, 3, 0, 5, 0, 0, 0, 0],
   L2 = [1, 2, 3, 4, 5, 6, 7, 8] .

这就是我得到的但我想要truefalse 如果L2 有3 作为第二个元素,5 作为第四个元素等等。0s 被忽略,那就是“过滤”条件。 我从输入中知道的是 L1 和 L2 总是长度=8,只有 L1 有0s。

我的代码是:

filter(_,_,9).
filter([Y|T],V2,Row):-
    Y=:=0,
    NewRow is Row + 1,
    filter([Y|T],V2,NewRow).

filter([Y|T],V2,Row):-
    Y=\=0,
    nth(Row,[Y|T],X1),
    nth(Row,V2,X2),
    X1=:=X2,
    NewRow is Row + 1,
    filter([Y|T],V2,NewRow).


nth(1,[X|_],X).  
nth(N,[_|T],R):- M is N-1, nth(M,T,R).

我知道有更好的方法来执行该功能,例如将第一个元素的第一个元素与第二个的第 n 个元素进行比较,并使用递归删除第一个元素的头部,但我只想知道为什么我没有得到truefalse,或任何“返回”值。

有人可以帮我吗?,搞定了

新代码:

filter([],R,_,R).
filter([Y|T],V2,Row,R):-
Y=:=0,
NewRow is Row + 1,
filter(T,V2,NewRow,R).

filter([Y|T],V2,Row,R):-
Y=\=0,
nth(Row,V2,X2),
Y=:=X2,
NewRow is Row + 1,
filter(T,V2,NewRow,R).

预期行为示例:

permutation([1,2,3,4,5,6,7,8],X),filter([1,2,3,4,0,0,0,0],X,1,R).
X = R, R = [1, 2, 3, 4, 5, 6, 7, 8] ;
X = R, R = [1, 2, 3, 4, 5, 6, 8, 7] ;
X = R, R = [1, 2, 3, 4, 5, 7, 6, 8] ;
X = R, R = [1, 2, 3, 4, 5, 7, 8, 6] .

现在我可以得到所有以 1,2,3,4 开头的排列。 如果有人知道实现相同目标的更好方法,请分享,但我已经得到了我需要的东西 =)。

【问题讨论】:

  • 我不明白发生了什么,但我添加了第 n 个谓词,但它缺少我添加的一些文本 O.o,你知道我的代码有什么问题吗?
  • 第三个参数它只是一个计数器,我知道 V1 和 v2 的 lgenth 将始终为 8,并且基本情况在那里,它在过滤器之后,我只是将 0 更改为 1跨度>

标签: prolog


【解决方案1】:

似乎对于 maplist/3 来说是一项完美的任务

filter(L1, L2, _) :-
  maplist(skip_or_match, L1, L2).

skip_or_match(E1, E2) :- E1 == 0 ; E1 == E2.

产量

?- permutation([1,2,3,4,5,6,7,8],X),filter([1,2,3,4,0,0,0,0],X,_).
X = [1, 2, 3, 4, 5, 6, 7, 8] ;
X = [1, 2, 3, 4, 5, 6, 8, 7] ;
X = [1, 2, 3, 4, 5, 7, 6, 8] ;
X = [1, 2, 3, 4, 5, 7, 8, 6] ;
...

我们可以使用 Prolog 工具更有用地做到这一点 - 即,使用 anonymus variable 来表达 don't care

那么filter/N就是maplist的一个简单应用:

?- permutation([1,2,3,4,5,6,7,8],X),maplist(=,[1,2,3,4,_,_,_,_],X).
X = [1, 2, 3, 4, 5, 6, 7, 8] ;
X = [1, 2, 3, 4, 5, 6, 8, 7] ;
X = [1, 2, 3, 4, 5, 7, 6, 8] ;
X = [1, 2, 3, 4, 5, 7, 8, 6] ;
...

【讨论】:

  • 谢谢,我知道我忘记了什么,maplist 以正确的方式完成了我需要的工作
【解决方案2】:

您的代码始终测试过滤列表的第一项是否为零。例如,查看第二个值时的情况:

filter([0,3,0,5,0,0,0,0], [1,2,3,4,5,6,7,8], 2).

此调用将执行以下统一:

# first case: obvious fail…
filter([0,3,0,5,0,0,0,0], [1,2,3,4,5,6,7,8], 2) =\= filter(_, _, 9).

# second case:
filter([0,3,0,5,0,0,0,0], [1,2,3,4,5,6,7,8], 2) = filter([Y|T],V2,Row).
# unification succeeds with substitutions:
    Y = 0
    T = [3,0,5,0,0,0,0]
    V2 = [1,2,3,4,5,6,7,8]
    Row = 2
# and what happens next?
    Y =:= 0 # success!

您可能想在这里检查 [Y|T] 的 second 元素是否为零;相反,您正在检查第一个。如果您想在不更改其余代码的情况下修复它,则应改为执行与 X1 的比较:

filter(V1,V2,Row):-
    nth(Row, V1, X1),
    X1 =:= 0,
    NewRow is Row + 1,
    filter(V1,V2,NewRow).

filter(V1,V2,Row):-
    nth(Row,V1,X1),
    X1=\=0,
    nth(Row,V2,X2),
    X1=:=X2,
    NewRow is Row + 1,
    filter(V1,V2,NewRow).

另外,还有一件事我认为你可能还没有在 Prolog 中得到。如果谓词失败,Prolog 确实会打印 false 并停止计算。但是如果一个谓词成功,有两种情况:

  • 如果您的查询中没有变量,Prolog 将打印 true
  • 如果您的查询中有任何变量,Prolog 不会打印true。相反,它会打印变量的值。这算作true

在您的情况下,Prolog 实际上从您的谓词中“返回”true——除了因为您在查询中使用了变量,它会打印它们的值而不是打印 true

【讨论】:

  • 嗨,刚刚解决了,我将添加代码和示例,但我实际上想比较以检查 V1 的第一个元素是否为 0,因为在这种情况下我忽略它并继续比较下一个元素,我只关心那些元素!= 0
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-29
  • 1970-01-01
  • 2016-11-08
相关资源
最近更新 更多