2

末尾再帰であることがわかっている関数があります。しかし、私がそれを定義する方法のために、コンパイラーは、関数が非テール位置で再帰呼び出しを行うことについて不平を言います。これが機能です。

@tailrec
def travel: (Int, List[Char]) => Int = {
    case (n,        Nil) => n
    case (n, '~' :: sls) => travel(0, sls)
    case (n, '^' :: sls) => travel(max(n-1,0), sls)
    case (n, '>' :: sls) => travel(n+1, sls)
    case (_,  s  :: sls) => throw new IllegalArgumentException("Illegal selector '" + s + "'")
}

私は得る

error: could not optimize @tailrec annotated method travel: it contains a recursive call not in tail position
def travel: (Int, List[Char]) => Int = {

このように書くとうまくいきます。

@tailrec
def travel(n:Int, l:List[Char]): Int = (n,l) match {
    case (n,        Nil) => n
    case (n, '~' :: sls) => travel(0, sls)
    case (n, '^' :: sls) => travel(max(n-1,0), sls)
    case (n, '>' :: sls) => travel(n+1, sls)
    case (_,  s  :: sls) => throw new IllegalArgumentException("Illegal selector '" + s + "'")
}

def: (Input) => Output = {}型宣言のスタイルと関係があると思います。ネストされた一致やタプルでの一致を書き込むよりも見た目がきれいなので、これを使用します。

4

1 に答える 1

7

2つは同じではありません。最初のケースでは、メソッドは関数を生成し、それがメソッドを再度呼び出します(関数などを生成します)。つまり、最初のケースでFunction1[(Int, List[Char]), Int]呼び出すたびに、の新しいインスタンスを作成します。travel当然のことながら、これをジャンプ命令に変換することはできません。(理論的には可能ですが、これらのオブジェクトの作成をすべて元に戻す必要があるため、分析は非常に複雑になります。)

2番目のケースでは、それはそれ自体を呼び出すメソッドであり、ジャンプに変換できます。

于 2012-03-15T16:03:07.500 に答える