Recursion 递归谓词在到达基本情况后继续
我正在尝试编写一个名为“range”的谓词,它在指定的范围内创建一个int列表 例如:Recursion 递归谓词在到达基本情况后继续,recursion,prolog,Recursion,Prolog,我正在尝试编写一个名为“range”的谓词,它在指定的范围内创建一个int列表 例如: range(4,9, L). L = [4,5,6,7,8,9] 我编写的谓词似乎工作正常,但当它完成时,我能够点击“下一步”,然后返回: L=[4,5,6,7,8,9,_1200 | u 1202] 这是我的密码: range(Low, Low, [Low]). %base case, if low and high are equal range(Low, High, [H|T]):- Low
range(4,9, L).
L = [4,5,6,7,8,9]
我编写的谓词似乎工作正常,但当它完成时,我能够点击“下一步”,然后返回:
L=[4,5,6,7,8,9,_1200 | u 1202]
这是我的密码:
range(Low, Low, [Low]). %base case, if low and high are equal
range(Low, High, [H|T]):-
Low > High,
!; %if low is greater than high cut
H is Low, %set the head of the list
Num is Low + 1, %increment low by 1
range(Num, High, T). %recursive call
如果给定的范围无效,我还希望它返回一个空列表。例如:
射程(10,4,L)
应该返回一个空列表。相反,我得到的是:
L=[U 1164 | U 1166]
我如何调整它,使其返回一个空列表,而不是(我假设是)头部和尾部的地址
以下是我在跟踪时看到的情况:
例如,您可以简化控制流程
range(Low, Low, [Low]). %base case, if low and high are equal
range(Low, High, [Low|T]):- %set the head of the list
Low < High,
Num is Low + 1, %increment low by 1
range(Num, High, T). %build the tail
但这将为每个计算的元素留下一个无用的choicepoint
编辑
这里有一种可能会为您的需求提供一个空列表:
range(Low, High, R):-
( Low > High
-> R = []
; R = [Low|T],
Num is Low + 1,
range(Num, High, T)
).
注意,我删除了第一个子句(基本递归,现在由第一个分支覆盖),并使用了更易于阅读的“”构造。对于我们的代码片段,它相当于:
range(Low, High, R):-
( Low > High,
!, R = []
; R = [Low|T],
Num is Low + 1,
range(Num, High, T)
).
您在剪切(!
)后写了一个分号(;
),而不是逗号(,
)。分号在某种程度上相当于“逻辑or”,因此您可以这样写:
range(A, A, [A]).
range(A, B, [C|E]) :-
( A>B, !
; C is A,
D is A+1,
range(D, B, E)
).
对于范围(1,2,L)
基本上有两条路径可以产生一个解决方案(这不是标准的表示法,在这里它只是用来说明Prolog是如何获得结果的:
range(1, 2, [C|E])
C is 1,
D is 2,
range(2, 2, E) :-
range(2, 2, [2]). % we found a solution
range(2, 2, [C|E])
C is 2,
D is 3,
range(3, 2, E) :-
range(3, 2, [C|E])
3 > 2. % we found a solution
剪切不停止子句的执行,一个割表示PROLO将不再考虑该特定调用的下一个子句(因此,如果我们执行递归,割对递归本身没有影响),因为没有其他子句,所以这里的切割没有影响。 我们可以将代码简化为:
range(A, A, [A]).
range(A, B, [A|T]) :-
A < B,
A1 is A+1,
range(A1, B, T).
你在剪切处写了一个分号而不是逗号,但是剪切还是没用的。谢谢你,这很有帮助。我不完全理解剪切的作用,但我现在明白了。当我用无效参数运行它时,虽然我得到的是一个假而不是一个空列表,但有没有办法使它返回一个空列表?@Sauromayne:你的意思是
Start
大于Stop
?最后一个介于/3
之间的解决方案应该可以解决这个问题。感谢您告诉我如何简化它。因此,当我们强制失败时,它返回“false”的原因是什么如果我传递了无效的参数?有没有办法让它给出一个空的列表而不是假的好吧,那么我唯一的问题是,既然没有基本情况(至少我看到了),是什么阻止了它永远继续下去?假设它在Low为10,High为9时到达Low>High。然后它会做->R=[]哪一个只是将列表的尾部设置为空列表?是的,base子句是第一个分支。请注意,包含;
的子句可以重写为在两个子句中“拆分”它们。
range(A, A, [A]).
range(A, B, [A|T]) :-
A < B,
A1 is A+1,
range(A1, B, T).
range(A, B, L) :-
findall(X, between(A, B, X), L).