不需要担心如何正确地实现递归谓词!
只需将“递归部分”委托给same_length/2
、append/3
和length/2
:
duplicate_nth(N,Xs0,Xs1) :-
same_length([_|Xs0],Xs1),
Suffix = [X|_],
append(Prefix,Suffix,Xs0),
length([_|Prefix],N),
append(Prefix,[X|Suffix],Xs1).
示例查询:
?- N = 1,
Xs0 = [a,b,c,d],
duplicate_nth(N,Xs0,Xs1).
N = 1, Xs0 = [a,b,c,d], Xs1 = [a,a,b,c,d] % 只有一个解
; false.
让我们将上面的查询泛化并看到解决方案集增长!
?- Xs0 = [a,b,c,d],
duplicate_nth(N,Xs0,Xs1).
N = 1, Xs0 = [a,b,c,d], Xs1 = [a,a,b,c,d] % (与之前相同的解决方案)
; N = 2, Xs0 = [a,b,c,d], Xs1 = [a,b,b,c,d] % (新的解决方案)
; N = 3, Xs0 = [a,b,c,d], Xs1 = [a,b,c,c,d] % (新的解决方案)
; N = 4, Xs0 = [a,b,c,d], Xs1 = [a,b,c,d,d] % (新的解决方案)
; false.
请注意,duplicate_nth/3
在“另一个方向”上使用时也有效。
?- Xs1 = [a,b,b,c,d,d,e],
duplicate_nth(N,Xs0,Xs1).
N = 2, Xs1 = [a,b,b,c,d,d,e], Xs0 = [a,b,c,d,d,e]
; N = 5, Xs1 = [a,b,b,c,d,d,e], Xs0 = [a,b,b,c,d,e]
; false.
最后,让我们运行最通用的查询!
?- duplicate_nth(N,Xs0,Xs).
N = 1, Xs0 = [_A], Xs = [_A,_A]
; N = 1, Xs0 = [_A,_B], Xs = [_A,_A,_B]
; N = 2, Xs0 = [_A,_B], Xs = [_A,_B,_B]
; N = 1, Xs0 = [_A,_B,_C], Xs = [_A,_A,_B,_C]
; N = 2, Xs0 = [_A,_B,_C], Xs = [_A,_B,_B,_C]
; N = 3, Xs0 = [_A,_B,_C], Xs = [_A,_B,_C,_C]
; N = 1, Xs0 = [_A,_B,_C,_D], Xs = [_A,_A,_B,_C,_D]
...
想要快速实现公平的枚举?没问题!
append([X], List, Result)
时,它等同于Result = [X|List]
。在这种情况下,[H]
append[H|T]
就是[H|[H|T]]
,也就是[H,H|T]
。 - lurker