List Prolog递归从n为任意数的列表中删除n的倍数索引处的元素

List Prolog递归从n为任意数的列表中删除n的倍数索引处的元素,list,recursion,prolog,List,Recursion,Prolog,这是我第一次在这里问问题,但我有一个问题,我真的无法理解,那就是Prolog递归,特别是当它处理列表时。所以我要解决的任务是写一个drop谓词,它的工作原理如下。例如,drop([1,2,3,4,5,6,7,8,9],2,L)其中L=[1,3,5,7,9]和N=N其中元素位于位置N,2n,3n。。。。将被删除。列表从1开始是另一件需要注意的事情 以下是我迄今为止的尝试和思考过程: drop([], _, []). indexOf([X|_], X, 1). %Using 1 because t

这是我第一次在这里问问题,但我有一个问题,我真的无法理解,那就是Prolog递归,特别是当它处理列表时。所以我要解决的任务是写一个drop谓词,它的工作原理如下。例如,
drop([1,2,3,4,5,6,7,8,9],2,L)
其中
L=[1,3,5,7,9]
N=N
其中元素位于位置N,2n,3n。。。。将被删除。列表从1开始是另一件需要注意的事情

以下是我迄今为止的尝试和思考过程:

drop([], _, []).

indexOf([X|_], X, 1). %Using 1 because the question says the first element starts from 1.

indexOf([_|Ys], Y , I):-
    indexOf(Ys, Y, N),
    I is N + 1.

drop([X|Xs], Y, [X|_]) :-
    indexOf([X|Xs] , X , A),
    Z is A mod Y,
    Z \== 0.

drop([X|Xs], Y, Zs) :-
    %indexOf([X|Xs], X, A),
    drop(Xs, Y, Zs).
我创建了一个
indexOf
谓词来查找从1开始的元素索引。接下来,我的想法是使用我的第一个drop递归案例(在上面的代码中,它是第五个案例)来检查元素的位置在除以
Y
(第二个输入)时是否返回零的余数。如果未返回零的余数,则
X
将保留在列表中,并且不会被删除。然后,prolog转到第二个drop递归案例,该案例只有在
Z=0
时才能到达,它将从列表中删除
X
以返回
Z
s。本质上,索引为n,2n,3n的元素。。。如果被
Y
(第二次输入)除后未返回零的余数,则
indexOf
返回的值将被删除

目前我还并没有学会这门课的这一点。如果有人能给我指出正确的方向,我将不胜感激。我已经为此工作了将近一天


我仍在尝试适应这种编程范式中的逻辑和声明性思维。如果您能与我分享,我将不胜感激,您个人是如何掌握逻辑编程的?

首先,看看您的方法,使用
索引/3
有一个缺陷。也就是说,在一个给定的时间点上,当您需要知道要删除的内容的索引时,在您找到它之前,您还不知道该项目是什么。此时,索引为
1

这是以下规则的一个问题:

drop([X|Xs], Y, [X|_]) :-
    indexOf([X|Xs], X, A),
    Z is A mod Y,
    Z \== 0.
第一个子查询:
indexOf([X | Xs],X,A)
第一次尝试时将成功使用
A=1
,根据定义(当然,
X
在列表
[X | Xs]中有索引
1
。当它成功时,下一行
Z是mod Y
产生
1
,因为
1 mod Y
总是
1
如果
Y>0
。因此,在这种情况下,
Z\==0
总是成功的

因此,您得到的结果是:
[X |!]
其中
X
是列表的第一个元素。因此,您得到的第一个解决方案,例如,
drop([1,2,3,4],2,L)。
L=[1 |
。您的第三个
drop/3
谓词子句只会递归到列表中的下一个元素,因此它将以相同的方式继承第二个子句,从而产生,
L=[2| |]
,依此类推

从上面开始,这里有一个方法来思考这样的问题

辅助谓词

我知道我想删除每一个
N
-th元素,因此有一个计数器会很有帮助,这样每当它到达
N
时,我都会忽略该元素。这是通过一个辅助谓词
drop/4
完成的,除了原始
N
之外,它还将有一个循环计数器:

drop(L, N, R) :-
    drop(L, N, 1, R).   % Start counter at 1
基本规则

如果我从空列表中删除任何元素,我将得到空列表。我删除的元素不重要。这表示为:

drop([], _, _, []).
您已经正确表达了此规则。以上是4参数版本

递归规则1-第N个元素
N
-th

我有一个列表
[X | Xs]
,并且
X
N
-th元素索引,如果我跳过
X
,将索引计数器重置为
1
,并从
Xs
中删除
N
-th元素,那么结果就是
R

递归规则2-除
N
-th元素之外

我有一个列表
[X | Xs]
X
A
-th元素(
N
),如果我增加我的索引计数器(
A
),并用我更新的索引计数器从
Xs
中删除
N
-th元素,那么结果就是
[X | R]

drop([X|Xs],N,A[X|R]):-
A

这些都是需要的规则(共4条)。

你的第二个drop谓词在结果的尾部有
,这是不好的。这意味着你的结果会有匿名变量。所以你显然不是这个意思。把这些看作规则,并试着这样读。
drop([X|Xs],Y[X||u]):-…
是列表
[X | Xs]
加上
Y
-th元素被删除是
[X |
如果……是什么使这成为事实?当然你需要
Y>1
,但是
[X |
需要一个真正的尾部,尾部的值将由你的规则决定。
indexOf([X | Xs],X,a)的第一个结果不是
a
始终是
A=1
索引策略的一个谬误是,在你到达那里之前,你并不真正知道第
Y
-th元素是什么,所以你不需要它来获取它的索引。你真的只需要一个简单的计数器。谢谢你的回答!在我再次尝试时看到了这一点今天早上,我在看gtrace,不明白为什么我的结果是[a | U G264]。多亏了你的第一句话,我现在终于明白了。我不应该在结果中使用匿名变量,因为我需要它来实例化/存储我的结果。是的!今天早上我注意到了使用indexOf策略的谬误,我尝试使用累加器作为简单计数器,但无法让它工作。不是真的
drop([_|Xs], N, N, R) :-   % I don't care what the element is; I drop it
    drop(Xs, N, 1, R).
drop([X|Xs], N, A, [X|R]) :-
    A < N,
    NextA is A + 1,
    drop(Xs, N, NextA, R).