只是刚刚开始学习prolog所以请耐心等待我们。 我只是涉及一点点递归,想要制作一个重复字符串N次的函数。
到目前为止,这是我的代码:
printn(N,X):-
N is N-1,
write(X),
N > 0,
printn(N,X).
我只是得到了错误的回复,有人可以解释一下吗? 谢谢
**** **** EDIT 工作代码
printn(N,X):-
M is N-1,
print(X),
N > 0,
nl,
printn(M,X).
答案 0 :(得分:3)
若要多次打印,您可以使用forall
和between
,如下所示:
打印“foo”三次
?- forall(between(1, 3, _), format("foo\n")).
foo
foo
foo
true.
这是多次出现副作用的最简洁方法(显式打印是副作用)。
如果您真的坚持使用递归,请考虑使用succ/2
倒数到零,然后失败:
do_n(Goal, N) :-
succ(N0, N),
Goal,
do_n(Goal, N0).
使用此谓词:
?- do_n(format("foo\n"), 3).
foo
foo
foo
false.
它最终失败了,这也是问题中你的“工作代码”所做的。例如,你可以这样做:
do_n(Goal, N) :-
( succ(N0, N)
-> Goal,
do_n(Goal, N0)
; true
).
这一切都假设你的问题是关于a)做某事(副作用) n 次或b)递归。如果有什么东西你想要那些 n 次,为什么不呢:
repeat_n(X, N, List) :-
length(List, N),
maplist(=(X), List).
现在:
?- repeat(foo, 3, List).
List = [foo, foo, foo].
就在那里,你拥有它:foo
打印三次。
当你有一个递归数据结构时,递归是很好的,因为你可以使用你推理的结构上的模式匹配来定义递归步骤和最终条件。整数不是这样的结构。
但是,您可以使用类似库(clpfd)的东西来进一步了解。例如:
:- use_module(library(clpfd)).
do_n(Goal, N) :-
zcompare(Order, 0, N),
do_n_(Order, Goal, N).
do_n_(=, _, _).
do_n_(<, Goal, N) :-
N0 #= N - 1,
Goal,
do_n(Goal, N0).
现在不会有任何额外的选择:
?- do_n(format("foo\n"), 3).
foo
foo
foo
true.
?- do_n(format("foo\n"), 0).
true.
?- do_n(format("foo\n"), -1).
false.
但你也可以这样做:
do_n(Goal, N) :-
length(L, N),
do_n_(L, Goal).
do_n_([], _).
do_n_([_|L], Goal) :-
Goal,
do_n_(L, Goal).
使用非负整数创建列表,然后使用该列表进行递归。这可能是最通用的解决方案:
?- do_n(format("foo\n"), 2).
foo
foo
true.
但也适用于自由变量:
?- do_n(format("foo\n"), N).
N = 0 ;
foo
N = 1 ;
foo
foo
N = 2 ;
foo
foo
foo
N = 3 . % and so on
最重要的是,在Prolog中,在确定如何解决问题之前,您确实需要了解解决的问题。我展示的每个解决方案都在某些环境中使用。我确信还有其他方法可以做到。另一个答案显示了另一种方法。
(注意:所有这些技术的例子都在Stackoverflow上有更详细的答案。如果有人愿意添加链接,欢迎你编辑我的答案。)
答案 1 :(得分:0)
只需改变一些事项:
printn(0,_).
printn(N,X):-
N > 0,
N1 is N-1,
writeln(X),
printn(N1,X).
你需要有一个不同的变量N1,因为N被实例化了,你还需要N = 0的基本情况,你只需添加printn(0,_).
子句就可以返回true。