2011-07-02 8 views
1

私は最近、面白いが厄介なF Sharpの動きに直面した。 [1]によれば、 "F#は自動的にパラメータを取らない関数の値をキャッシュする"。これは良いアイデアのようだが、乱数を生成するためのラッパー関数を試してみると私にとっては問題を引き起こしている。特定の機能のFSharpファンクションキャッシングをオフにしますか?

例として、この質問の最後に2つの異なる機能があります。最初の関数 "getRand"はパラメータを取りませんが、残念ながら常に同じ番号を返します。 2番目の関数 "getRand2"は、呼び出されるたびに新しい乱数を生成すると期待していますが、無意味で無視される余分なパラメータが必要です。

可能であれば、私はgetRand2の機能を持っていますが、getRandの利便性を望みます。 getRand2に適用できるコンパイラ・ディレクティブまたは特別なキーワードがあります。これにより、関数キャッシュ機能がオフになり、getRand2のように動作します。おかげで

ショーン
注:答えはすでに[1]、私はちょうど今それを見ていないよに表示されている場合は、私を許してください。
[1] - http://en.wikibooks.org/wiki/F_Sharp_Programming/Caching

(* Always returns the same number *) 
let getRand = 
    let seed = int32(System.DateTime.Now.Ticks) 
    let randGen = new System.Random(seed) 
    randGen.Next() 

(* Works as expected except I need an annoying extra parameter *) 
let getRand2 dummyParam = 
    let seed = int32(System.DateTime.Now.Ticks) 
    let randGen = new System.Random(seed) 
    randGen.Next() 

(* Outputs three "identical" numbers to console *) 
System.Console.WriteLine(
    "Parameterless getRand always outputs same number.") 
System.Console.WriteLine(getRand) 
System.Threading.Thread.Sleep(100) 
System.Console.WriteLine(getRand) 
System.Threading.Thread.Sleep(100) 
System.Console.WriteLine(getRand) 
System.Console.WriteLine() 

(* Outputs three "different" numbers to console *) 
System.Console.WriteLine(
    "GetRand2 works as expected even though second dummy param is always the same.") 
System.Console.WriteLine(getRand2 0) 
System.Threading.Thread.Sleep(100) 
System.Console.WriteLine(getRand2 0) 
System.Threading.Thread.Sleep(100) 
System.Console.WriteLine(getRand2 0) 
System.Console.WriteLine() 

答えて

5

だけビットを明確にするために、私は、フレーズ「パラメータを取らない関数は」誤解を招くだと思います。定義によって、関数は関数の領域の値を関数の範囲の値にマップするので、すべての関数はパラメータを取ります。あなたのケースでは、getRandは関数にバインドされていません。値はintです。

私が正しくあなたの質問を理解していれば、私はあなたがまだ機能(getRand()だけでなく、getRand)としてgetRandを呼び出す必要がありますが、これを回避する方法はありません

let getRand =  
    let seed = int System.DateTime.Now.Ticks  
    let randGen = new System.Random(seed) 
    fun() -> randGen.Next() 

をしたいと思います - intの値が常に同じままであるという事実は、プログラムについての推論の重要な特徴です。

あなたはgetRandの私のバージョンとほとんど同じ方法であなたのgetRand2機能を使用することができます:あなたは、単位値()を渡すことができることを意味し、F#は関数がジェネリックになり、体内のdummyParamを使用していないので、あなたが望むなら、議論。 の場合、getRand2関数は呼び出されるたびに新しい乱数ジェネレータを作成するという点で壊れています。

let x,y = (getRand2(), getRand2()) 

それは無名関数のスコープの外seedrandGenを定義することが重要である理由です:これは、あなたが1つの目盛り以内に2回それを呼び出す場合は、あなたが同じ答えを得ることを意味します。

+0

私はあなたが正しいと思います。私のgetRandのシグネチャを "let getRand ="から "let getRand()="に変更することができますが、それでもgetRandを関数として呼び出す必要があることを認識するのに役立ちました(getRand()、getRandだけではない)...これを回避する方法はありません。 - kvbからの引用。それにもかかわらず、他の誰かがより良い返答を投稿しない限り、あなたは私の回答投票を得るでしょう! –

+0

@Shawn - あなたのコメントからいくつかの詳細を追加しました。 – kvb

+0

* my * getRandが関数にバインドされておらず、単純にint型の値であるというあなたの推論を適用した場合、なぜ同じ値が返され続けるのかが分かります。私はこの説明に感謝します。さらに、* my * getRand2関数が壊れているというあなたの声明に同意します。あなたは正しいです、私は必ずシードを定義し、randGenはgetRandスタイルの構造体を介して返すことを選択した関数の範囲外です。この時点で、私はあなたがこの質問を地面に釘付けにしたと信じています。ありがとう! –