简体   繁体   English

为什么这个函数不是尾递归的?

[英]Why is this function not tail recursive?

I'm writing a simple contains method for a list like structure.我正在为类似结构的列表编写一个简单的 contains 方法。 I want it to be optimized for tail recursion but can't figure out why the compiler is complaining.我希望它针对尾递归进行优化,但无法弄清楚编译器为什么会抱怨。

The Cons case is tail recursive but not the repeat case even though they're making the same call on the same data structure. Cons 情况是尾递归但不是重复情况,即使它们对相同的数据结构进行相同的调用。 Maybe I'm not understanding tail recursion properly.也许我没有正确理解尾递归。 If someone could clear this up I would a grateful.如果有人能解决这个问题,我将不胜感激。

  final def contains[B >: A](target: B): Boolean = this match{
    case Empty => false
    case Cons( h, t ) => h == target || t.contains( target )
    case Repeat( _, l ) => l.contains( target )
  } 

A tail-recursive function is defined as one whose last statement is either returning a plain value or calling itself, and that has to be the only recursive call.尾递归函数被定义为最后一个语句要么返回一个普通值要么调用自身的函数,并且它必须是唯一的递归调用。

First, your function doesn't have recursive calls, because you are not calling contains function again.首先,您的函数没有递归调用,因为您没有再次调用contains函数 But, you are calling the contains method of another instance.但是,您正在调用另一个实例的contains方法
That can be solved, by moving the logic outside the class.这可以通过将逻辑移到类之外来解决。

However, there is another common problem.但是,还有另一个常见问题。
This: h == target || t.contains( target )这: h == target || t.contains( target ) h == target || t.contains( target ) is not a tail-recursive call, since the last operation is not the call to contains but the or ( || ) executed with its result. h == target || t.contains( target )不是尾递归调用,因为最后一个操作不是对contains的调用,而是对其结果执行的 or ( || )

Here is how you may refactor it.这是您可以重构它的方法。

def contains[A](list: MyList[A])(target: A): Boolean = {
  @annotation.tailrec
  def loop(remaining: MyList[A]): Boolean = 
    remaining match {
      case Empty => false
      case Cons(h, t) => if (h == target) true else loop(remaining = t)
      case Repeat(_, l) => loop(remaining = l)
    }
  loop(remaining = list)
}

If you still want the method on your class, you can forward it to call this helper function passing this as the initial value.如果你仍然想要你的类上的方法,你可以转发它来调用这个辅助函数,将this作为初始值传递。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM