1

私はかなり単純な末尾再帰関数であると信じているものを持っています。しかし、そうではないと@tailrec教えてくれます。

  @tailrec
  def _next(continue : String, current : List[Long], first : Boolean ) : Stream[Long]  = {
    current match {
      case head :: tail => head #:: _next(continue, tail, false) //this line breaks tailrec
      case Nil if first => empty
      case _ => {
        val (nc, nl) = getIds(continue)
        _next(nc, nl, true)
      }
    }
  }

それは私に

[error] could not optimize @tailrec annotated method _next: it contains a recursive call not in tail position
[error]  case head :: tail => head #:: _next(continue, tail, false)
[error]                                     ^

おそらく eclipse: から受け取った暗黙の通知に関係しています- Implicit conversions found: _next(continue, tail, false) => consWrapper(_next(continue, tail, false))が、残念ながら、それは問題の解決には役立っていません。

どうすればこれを修正できますか? また、ブラウニー ポイントの場合、これが末尾再帰になるとどこで間違ったのでしょうか?

4

1 に答える 1

4

問題は、コードの最後の操作が の呼び出しでは_nextなく、Streamcons 操作であること#::です。

1 つの解決策は、a を使用しStreamBuilderてストリームを構築し、これStreamBuilderをアキュムレータ変数として保持することです。

  @tailrec
  def _next(continue : String, current : List[Long], first : Boolean, acc: Stream.StreamBuilder[Long]) : Stream[Long]  = {
    current match {
      case head :: tail =>
        acc += head
        _next(continue, tail, false, acc)
      case Nil if first => acc.result
      case _ => {
        val (nc, nl) = getIds(continue)
        _next(nc, nl, true, acc)
      }
    }
  }

これは特に効率的ではありません。 の代わりにStreamBuilderを使用してコレクション全体を追加する場合は、 の方が適しています。このため、コードを次のように変更することを検討してください。++=+=

  @tailrec
  def _next(continue : String, current : List[Long], first : Boolean, acc: Stream.StreamBuilder[Long]) : Stream[Long]  = {
    current match {
      case Nil =>
        acc.result
      case list =>
        acc += list
        val (nc, nl) = getIds(continue)
        _next(nc, nl, true, acc)
    }
  }
于 2013-04-18T15:16:20.167 に答える