【问题标题】:Creating a tail recursive drop function in Prolog在 Prolog 中创建尾递归删除函数
【发布时间】:2021-06-22 04:15:21
【问题描述】:

我正在尝试在 prolog 中创建一个尾递归 drop/3。教给我们尾递归的方式(很差)甚至没有开始向我展示我需要如何解决这个问题。

据我所知,这是我唯一没有工作的东西,甚至不是尾递归的。我已经走到了尽头,所以任何帮助都将不胜感激。

drop(N, [], []).
drop(N, [A,As], Bs) :-
   integer(N), 
   N > 0,
   N1 is N - 1,
   Bs is As,
   drop(N1, As, Bs).

【问题讨论】:

  • 这是完美的尾递归。在递归调用之后不需要计算 drop/3 中的任何内容。如果编译器足够精炼,它可以将其优化为一个常量堆栈空间循环,而不是每次调用时增加 1 个堆栈帧。
  • 不确定这应该做什么。第一个参数有一个倒计时到 0(所以你最好为第一个子句写 drop(0, [], []).)。而且我确定在第二个子句头部的 arg 2 中错误地使用了逗号,而不是 |Bs is As 肯定是错误的,尾递归调用本身也是错误的。

标签: recursion prolog tail-recursion


【解决方案1】:

你的问题是:

  • [A,As] 是一个 2 元素列表(例如,[ alpha, bravo ]),而不是将列表分成头部和尾部。 [ H | T ] 应用于列表[a,b,c] 时,产生HaT[b,c]
  • is/2 进行算术运算,所以 Bs is As 不起作用。 . .如果是这样,您将统一结果:一个序言变量,一旦统一就不再是变量,因此不能重新分配。

所以,假设你想实现这个drop/3,试试这个:

drop( _ , []    , [] ) .  % allows `drop(3, [a,b], R)` to succeed
drop( 0 , R     , R  ) .  % dropping the first 0 element from a list returns the same list
drop( N , [_|T] , R  ) :- % otherwise . . .
  integer(N) ,            % - given that N is an integer, and
  N > 0 ,                 % - given that N is positive, then
  N1 is N-1 ,             % - we decrement N, and
  drop( N1, T , R )       % - recurse down, discarding the head (1st element) of the list
  .                       % Easy!

请注意,如果您尝试从 2 元素列表中删除 3 个元素,这将失败。允许该案例成功是一个简单的更改。

使这个尾递归的原因是唯一重要的状态是递归调用之间传递的内容。这意味着可以重用堆栈帧。而且由于没有新的帧被压入调用堆栈,这实际上将递归函数调用转变为迭代。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-04
    • 2020-12-22
    相关资源
    最近更新 更多