这是我第一次在这里问一个问题,但是我有一个问题,我真的无法解决这个问题,特别是当它处理列表时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递归情况(在上面的代码中是第5个案例)来检查并查看元素的位置在除以Y
(第二个)时是否返回零的余数输入)。如果它没有返回零的余数,则X
保留在列表中并且不会被删除。然后,prolog转到第二个递归递归的情况,该情况只能在Z=0
时到达,并且它将从列表中删除X
以返回Z
s。本质上,indexOf
返回的索引为n,2n,3n ...的元素如果在除以Y
(第二个输入)时没有返回零的余数,则将被删除。 / p>
此刻我还没有学过Cut。如果有人能指出我正确的方向,我将不胜感激。我已经在这方面工作了将近一天。
我仍在尝试在这种编程范式中调整逻辑和陈述性思维。如果你能和我分享,我很感激,你个人如何掌握逻辑编程?
答案 0 :(得分:0)
首先,看看你的方法,使用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
在列表{{1}中有索引1
成功后,下一行[X|Xs]
会产生Z is A 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
时我都会忽略该元素。这是通过辅助谓词N
完成的,除了原始drop/4
之外,它还有一个重复的计数器:
N
基本规则
如果我从空列表中删除任何元素,我会得到空列表。我放弃的元素并不重要。这表达为:
drop(L, N, R) :-
drop(L, N, 1, R). % Start counter at 1
您已经正确表达了此规则。以上是4参数版本。
递归规则1 - drop([], _, _, []).
- 元素
我有列表N
,[X|Xs]
是第X
个元素索引,如果我跳过N
,结果为R
,将我的索引计数器重置为X
,并从1
中删除N
个元素:
Xs
递归规则2 - 除了drop([_|Xs], N, N, R) :- % I don't care what the element is; I drop it
drop(Xs, N, 1, R).
- 元素
我有列表N
而[X|Xs]
是X
- 元素(< A
),那么结果是N
我增加了我的索引计数器([X|R]
),并使用我更新的索引计数器删除A
中的N
元素:
Xs
这些是所有必需的规则(其中4个)。