Отключить кэширование функции FSharp для определенной функции? - PullRequest
2 голосов
/ 02 июля 2011

Недавно я столкнулся с интересным, но раздражающим поведением F Sharp. Согласно [1], «F # автоматически кэширует значение любой функции, которая не принимает параметров». Это кажется хорошей идеей, но это вызывает у меня проблемы, так как я пытаюсь найти функцию-обертку для генерации случайных чисел.

Например, в конце этого вопроса у меня есть две разные функции в коде. Первая функция «getRand» не принимает параметров, но, к сожалению, всегда возвращает одно и то же число. Вторая функция «getRand2» работает так, как и следовало ожидать, генерируя новое случайное число каждый раз, когда она вызывается, но она досадно принимает бесполезный и игнорируемый дополнительный параметр.

Если возможно, я хотел бы иметь функциональность getRand2, но удобство getRand. Есть ли директива компилятора или специальное ключевое слово, которое я могу применить к getRand, чтобы отключить его функции кэширования функций и тем самым заставить его вести себя как getRand2?

С благодарностью,

Shawn
Примечание: простите, если ответ уже появился в [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()

1 Ответ

6 голосов
/ 02 июля 2011

Просто для пояснения, я думаю, что фраза "функция, которая не принимает параметров" вводит в заблуждение. По определению, функция отображает значение из области функции в значение в диапазоне функции, поэтому все функции принимают параметры. В вашем случае getRand не привязан к функции, это просто значение типа int.

Если я правильно понимаю ваш вопрос, я думаю, что вы хотите сделать

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

Вам все еще нужно вызывать getRand как функцию (getRand(), а не просто getRand), но нет способа обойти эту проблему - тот факт, что значение int всегда остается неизменным, является критически важным функция рассуждений о программе.

Вы можете использовать вашу функцию getRand2 почти так же, как моя версия getRand: поскольку вы не используете dummyParam в теле, F # делает функцию универсальной, что означает, что вы можете передать значение единицы () в качестве аргумента, если хотите. Однако , ваша функция getRand2 не работает, так как она создает новый генератор случайных чисел при каждом вызове. Это означает, что если вы позвоните дважды в течение одного тика, вы получите один и тот же ответ:

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

Именно поэтому важно определить seed и randGen вне области действия анонимной функции.

...