Prolog编程中的问题
您好,我是Prolog新手,正在尝试用Prolog编写小程序以学习它 我已经写了一个程序来删除位置元素,意思是删除(List,2,Ans)将删除位置2,4,6,8的所有元素。。。。从列表中。。。下面是我的逻辑Prolog编程中的问题,prolog,Prolog,您好,我是Prolog新手,正在尝试用Prolog编写小程序以学习它 我已经写了一个程序来删除位置元素,意思是删除(List,2,Ans)将删除位置2,4,6,8的所有元素。。。。从列表中。。。下面是我的逻辑 remove(L,N,Ans):- length(L,LEN), T1 is 1 mod N, add(L,N,[],LEN,T1,Res). add(L,N,Ans,0,T,Ans). add([H|T],N,Ans,LEN,0,Res):- LEN1 is L
remove(L,N,Ans):-
length(L,LEN),
T1 is 1 mod N,
add(L,N,[],LEN,T1,Res).
add(L,N,Ans,0,T,Ans).
add([H|T],N,Ans,LEN,0,Res):-
LEN1 is LEN-1,
T1 is 1 mod N,
add(T,N,Ans,LEN1,T1,Res).
add([H|T],N,Ans,LEN,T,Res):-
T =\= 0, LEN =\= 0,
LEN1 is LEN-1,
T1 is T1+1,
T2 is T1 mod N,
append([H],Ans,Result),
add(T,N,Result,LEN1,T2,Res).
但每次我运行它时,在查找add时都会失败。下面是针对特定实例的程序跟踪
[trace] ?- remove([1,2,3,4,5,6,7,8],2,X).
Call: (6) remove([1, 2, 3, 4, 5, 6, 7, 8], 2, _G2941) ? creep
Call: (7) length([1, 2, 3, 4, 5, 6, 7, 8], _G3039) ? creep
Exit: (7) length([1, 2, 3, 4, 5, 6, 7, 8], 8) ? creep
Call: (7) _G3041 is 1 mod 2 ? creep
Exit: (7) 1 is 1 mod 2 ? creep
Call: (7) add([1, 2, 3, 4, 5, 6, 7, 8], 2, [], 8, 1, _G3046) ? creep
Fail: (7) add([1, 2, 3, 4, 5, 6, 7, 8], 2, [], 8, 1, _G3046) ? creep
Fail: (6) remove([1, 2, 3, 4, 5, 6, 7, 8], 2, _G2941) ? creep
false.
有人知道问题出在哪里吗?希望您能在代码中找到解决方法。我认为学习一门语言更好的方法实际上是调试它。。。潜伏者的评论已经让你走上了正确的轨道。但我想展示使用内置程序如何改变您的视角(当然,这对于任何语言都是正确的,不仅仅是Prolog) 当你 没有规则可以匹配,特别是T不能是列表和数字1
add([H|T],N,Ans,LEN,T,Res):-
也就是说,我不确定应该如何更正代码…一个常见的prolog习惯用法是使用“helper”谓词,它实际执行工作并携带 维护状态的一个或多个附加参数。在这种情况下,我们需要一个计数器来跟踪 我们在来源列表中的位置
remove( Xs , N , Ys ) :-
remove( Xs , 1 , N , Ys ). % Note the additional argument (our counter) initialized to 1
remove( [] , _ , _ , [] ) . % when we exhaust the source list, we're done.
remove( [X|Xs] , P , N , [X|Ys] ) :- % otherwise,
P mod N =\= 0 , % - if the current position is NOT a multiple of N,
P1 is P+1 , % - we increment the position,
remove(Xs,P1,N,Ys) % - and recurse down, adding the head of the list
. % to the result.
remove( [_|Xs] , P , N , Ys ) :- % otherwise,
P mod N =:= 0 , % - if the current position is a multiple of N,
P1 is P1+1 , % - increment the position,
remove(Xs,P1,N1,Ys) % - and recurse down, discarding the head of the list
. % Easy!
您可能会注意到一些重复的代码。本着保持干燥的精神,我们可以对其进行重构:
remove( [] , _ , _ , [] ) . % when we exhaust the source list, we're done.
remove( [X|Xs] , P , N , Ys ) :- % otherwise,
keep_or_discard(X,P,N,Ys,Y1) , % - decided whether to keep or discard the current list head
P1 is P+1 , % - increment the counter
remove( Xs , P1 , N , Y1 ) % - and recurse down.
.
keep_or_discard( _ , P , N , Ys , Ys ) :- % if P is a multiple of N
P mod N =:= 0 , % - discard X,
! . % - and eliminate the choice point.
keep_or_discard( X , _ , _ , Ys , [X|Ys] ) . % otherwise, we keep it.
有些人不喜欢使用切割来明确消除选择点,因此,我们也可以通过使用prolog的运算符来进行重构:
remove( [] , _ , _ , [] ) . % when we exhaust the source list, we're done.
remove( [X|Xs] , P , N , Ys ) :- % otherwise,
( P mod N =:= 0 % - if P is a multiple of N,
-> Y1 = Ys % - then we discard the list head
; [X|Y1] = Ys % - otherwise, we add it to the result list
) , % - and then ...
P1 is P+1 , % - increment the counter
remove( Xs , P1 , N , Y1 ) % - and recurse down.
.
当然,这两种重构是否比原始重构更清晰或更容易理解是个人的选择。但是在这种情况下,最后一个add将通过1与T的统一来选择。
1 mod N
总是1
如果N>1
不是吗?@潜伏者我不清楚它在调用Call时:(7)add([1,2,3,4,5,6,7,8],2,[],8,1,_G3046)?爬行…为什么它不能通过最后一次添加来细化这个目标或统一这个目标…是的…这很好,但我正在学习porlog的逻辑…并尝试从以下链接解决问题bagof/3
更适合这种解决方案,因为它也按预期处理变量。@JatinKhurana:当然,哟你是对的。请注意,我在我的代码片段中建议了一个表达式,它可以帮助你更正代码……你能告诉我为什么不能将7点的通话与最后一次添加统一起来……我已经厌倦了从最后1-2小时开始想象它。@JatinKhurana它不能将7点的通话统一起来,因为Carlo在他的回答中告诉你:你在尝试选择在第一个参数中使用T
作为列表,在第五个参数中使用数字。调用不匹配前两个add
子句,因为第四个或第五个参数都不是0
。它不匹配最后一个子句,因为第一个参数将T
实例化为[2,3,4,5,6,7,8]
第五个参数试图将T
实例化为1
。不能两者都是。您需要为第五个参数选择一个不同的变量名。您还需要修复T1是T1+1
。这很好……但我的问题是为什么它不统一add([1,2,3,4,5,6,7,8],2,[],8,1,_G3046)最后加上…为什么它是给假。。。。
remove( [] , _ , _ , [] ) . % when we exhaust the source list, we're done.
remove( [X|Xs] , P , N , Ys ) :- % otherwise,
keep_or_discard(X,P,N,Ys,Y1) , % - decided whether to keep or discard the current list head
P1 is P+1 , % - increment the counter
remove( Xs , P1 , N , Y1 ) % - and recurse down.
.
keep_or_discard( _ , P , N , Ys , Ys ) :- % if P is a multiple of N
P mod N =:= 0 , % - discard X,
! . % - and eliminate the choice point.
keep_or_discard( X , _ , _ , Ys , [X|Ys] ) . % otherwise, we keep it.
remove( [] , _ , _ , [] ) . % when we exhaust the source list, we're done.
remove( [X|Xs] , P , N , Ys ) :- % otherwise,
( P mod N =:= 0 % - if P is a multiple of N,
-> Y1 = Ys % - then we discard the list head
; [X|Y1] = Ys % - otherwise, we add it to the result list
) , % - and then ...
P1 is P+1 , % - increment the counter
remove( Xs , P1 , N , Y1 ) % - and recurse down.
.