【问题标题】:Recursion on Prolog [duplicate]Prolog上的递归[重复]
【发布时间】:2021-07-13 12:22:57
【问题描述】:

我正在尝试编写一个 Prolog 递归,它将返回以下数字表示:

1 --> s(0)

2 --> s(s(0))

3 --> s(s(s(0))) ...

我使用了以下代码:

retnum(s(0),1). %Stop Condition
retnum(S,Z):-
    retnum(s(S),Z1),
    Z is Z1+1.

但是当我尝试运行预测时:

retnum(A,2).

我得到结果 A=0,如果我继续,我会收到超出卡住限制的错误。 我期待得到一个结果 A = s(s(0))。 我还尝试添加额外的停止条件:retnum(0,0)。

知道我的错误在哪里以及是否有更好的方法吗?

【问题讨论】:

    标签: recursion prolog successor-arithmetics


    【解决方案1】:

    您错误地使用了递归调用。递归实例的参数应该小于原始参数(更一般地说:收敛到边界条件)。 这可能会给你你想要的:

    retnum(s(0), 1).
    retnum(s(S), Z) :-
        retnum(S, Z1),
        Z is Z1 + 1.
    

    但这更好。

    retnum1(s(0), 1).
    retnum1(s(S), Z) :-
        Z > 1, Z1 is Z - 1,
        retnum1(S, Z1).
    

    尝试trace/0 看看为什么会这样。

    【讨论】:

    • 这现在得到了retnum(A,2) 的正确答案,但此后仍会循环。
    • @false: 你是在建议retnum 除了retnum1 之外的另一种写法吗?
    • 我认为他在谈论retnum1(s(0), 1) :- !. 之类的东西,以防止出现选择点?我不知道这是“好”还是“坏”的做法,我对 Prolog 还是很陌生。
    • @rajashekar:要么手动进行(有很多容易出错的var/1 测试等),要么使用library(clpfd)
    • @MarkusWeninger:您的建议retnum1(s(0), 1) :- !. 将使retnum1(X, N) 的答案不完整。 retnum1(X, N), N = 2 现在会错误地失败。
    【解决方案2】:

    按照@false 的建议,最好的方法是使用library(clpfd)。但是,如果您不想使用该库,则可能的解决方案是考虑两种不同的情况:

    • 确定性情况 [要转换成Peano形式的自然N是一个常数]:从N开始,递归递减这个值,直到达到值 0(可以生成唯一解)。

    • 非确定性情况 [要转换成Peano形式的自然N是一个变量]:从0开始,递归递增这个值,产生一个新的自然N 在每一步(可以生成无限多的解决方案)。

    % nat(?Natural, ?Peano)
    
      nat(N, P) :-
         (  integer(N) -> nat_det(N, P)
         ;  var(N)     -> nat_nondet(N, P)).
    
      nat_det(0, 0) :- !.
      nat_det(N, s(P)) :-
         succ(M, N),
         nat_det(M, P).
    
      nat_nondet(0, 0).
      nat_nondet(N, s(P)) :-
         nat_nondet(M, P),
         succ(M, N).
    

    这里有一些例子:

    ?- nat(2, P).
    P = s(s(0)).
    
    ?- nat(2, s(s(0))).
    true.
    
    ?- nat(2, s(s(s(0)))).
    false.
    
    ?- nat(N, s(s(s(0)))).
    N = 3.
    
    ?- N = 4, nat(N, P).
    N = 4,
    P = s(s(s(s(0)))).
    
    ?- nat(N, P), N = 4, !. % we know that there exist only one solution!
    N = 4,
    P = s(s(s(s(0)))).
    
    ?- nat(N, P).
    N = P, P = 0 ;
    N = 1,
    P = s(0) ;
    N = 2,
    P = s(s(0)) ;
    N = 3,
    P = s(s(s(0))) ;
    ...
    

    【讨论】:

    • 奖励:此版本无法用于nat(1+0,X)
    • 是的,我只考虑了 X 是常数或变量的情况。无论如何,也可以扩展定义以处理数字表达式。
    • 没问题! 0+0 有许多其他定义失败但 1+0 成功
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    • 2014-06-16
    • 1970-01-01
    • 2017-04-26
    • 2018-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多