2017-03-05 16 views
3

私は、リストを2つのハーフに分割する機能を持っています。ここでこの分割機能はなぜ機能しますか?

は関数である。この文は(a::M, b::N)の作品、なぜ私は理解していない何

let rec split = function 
    | []  -> ([],[]) 
    | [a]  -> ([a],[]) 
    | a::b::cs -> let (M,N) = split cs 
       (a::M, b::N) 

です。この文を実行する前に再帰関数を呼び出すのではないでしょうか?その声明は決して実行されるべきではありませんか?

+3

短いリストの実行フローを書き留めてみると、その動作方法がわかります。ある時点で '[]'と '[a]'とのマッチングを開始します。これにより、再帰が最初の呼び出しまですべて展開されます。 – MarcinJuraszek

+0

@MarcinJuraszek私はそれを間違ってやっていたので、私は混乱していたのですが、今は理解しています。ありがとう! – name

+0

あなたの関数が末尾再帰的でないということが起こっているだけです。 (尾の再帰関数では、再帰呼び出しは関数の最後のものです)。 F#は、非末尾再帰関数を扱うことができます。しかし、あなたの関数はテール再帰的ではないので、長いリストを提供するとスタックは爆発します。このリストで 'let xs = [1..1000000]'と試してみてください。これを修正するには、累積パターン(または他の手法)を使用して関数を書き直して、尾を再帰的にする必要があります。テイル再帰関数はスタックを吹き飛ばすことはありません。 – Soldalma

答えて

6

私たちはその文を実行する前に再帰関数を呼び出していませんか?

はい。

これは決して実行しないでください。

再帰が無限であった場合のみ、再帰が無限であった場合のみ。つまり、再帰呼び出しが終了すると、(a::M, b::N)が評価されます。ここで起こって無限

split [1;2;3] 
= let (M,N) = split [3] 
    (1::M, 2::N) 
= let (M,N) = ([3], []) 
    (1::M, 2::N) 
= (1::[3], 2::[]) 
= ([1;3], [2]) 

ナッシング:例として

は、コールsplit [1;2;3]を検討してください。

+0

私はこの例を間違ってやっていたので、私は混乱していました。ご協力ありがとうございました! – name

関連する問題