2016-10-15 9 views
-5

どのようにして、以下の関数を通常の再帰とテール再帰で書くことができますか?スカラ再帰

+1

あなた自身で試しましたか?はいの場合..どこにいらっしゃいますか? – pamu

+0

大きな質問です。 – Det

答えて

2

ここには基本的な再帰バージョンがあります。

def satisfiesAllIt(x: List[Any], test: Any => Boolean): Boolean = 
    if (x.isEmpty) true 
    else if(test(x.head)) satisfiesAllIt(x.tail, test) && true 
    else false 

ここでは尾部再帰バージョンがあります。

def satisfiesAllIt(x: List[Any], test: Any => Boolean): Boolean = 
    if (x.isEmpty) true 
    else if(test(x.head)) satisfiesAllIt(x.tail, test) 
    else false 

これは、標準ライブラリを学習した後の作業です。

def satisfiesAllIt(x: List[_], test: Any => Boolean): Boolean = x.forall(test) 

@The典型ポールは(彼はしばしばように)良い点を作り、代替手段を提供してきました。

// basic recursive 
def satisfiesAllA(x: List[Any], test: Any => Boolean): Boolean = 
    x.isEmpty || satisfiesAllA(x.tail, test) && test(x.head) 

// tail recursive 
def satisfiesAllB(x: List[Any], test: Any => Boolean): Boolean = 
    x.isEmpty || test(x.head) && satisfiesAllB(x.tail, test) 

は、我々はすべて実際にそれを指摘せずに、周りに踊っているのか、基本と尾再帰間の定義の違いは次のとおりです。再帰呼び出しが戻る(計算/評価後に行われる任意のより多くの「仕事」があるかどう/ etc。) ではなく、テール再帰的です。

+1

' && true''を非末尾再帰にするのはちょっとハックです:)もし、非末尾再帰的なものを使いたいのであれば、OPの関数をエミュレートしてカウントするのが良いでしょうか? –

+0

@TheArchetypalPaul、私は同意しない。コアの違いをよりよく説明できるように、2つのバージョンをできるだけ似ている方が有益であると感じました。 – jwvh

+1

私はそれが違いを説明しないと思います。 "&& ttrue"はアルゴリズム上の理由ではありません '= x、isEmpty || (satisfiesAll(x.tail、test)&& test(x.head)) 'は、簡潔で非末尾再帰的なものですか? –

0

satisfiesAllItの末尾再帰バージョンです。リストが終了するまで関数を再帰的に呼び出し、テストが失敗した場合はfalseを返します。

def satisfiesAllIt(x: List[Any], test: Any => Boolean): Boolean = xs match { 
    case Nil => true 
    case x :: xs => 
    if (test(x)) satisfiesAllIt(xs, test) else false 
} 
+0

あなたはそれらを数える必要はありません。あなたはちょうど最初のものが満足していないときに停止する必要があります –

+0

@TheArchetypalPaulあなたは正しいです。それを修正しました:) – pamu

+0

あなたが 'helper'に' test'を渡すと、ヘルパー関数は必要ありませんしかし、ただ 'satisfiesAllIt'を持つことができます:) –