Можливі дублікати:
Поєднайте запам'ятовування та рекурсію хвоста
Отже, наступним є код, який я написав, хвостовий виклик оптимізований за допомогою змінної накопичення
let rec counter init count =
if init = 1 then count + 1 else
match init with
| Even value -> (counter (value/2) (1 + count))
| Odd value -> (counter ((3 * value) + 1) (count+1))
let SeqBuilder (initval:int) : int =
counter initval 0
Як це запам'ятати? Проблема, з якою я зіткнувся, коли я намагався запам’ятати, це те, що рекурсивний виклик повинен перейти до об'єкта запам'ятовування, тому у вас повинен бути… рекурсивний об’єкт?
Або це набагато простіше, і я просто недосвідчений?
Відповіді:
3 для відповіді № 1F # дозволяє визначити a рекурсивне значення (наприклад, рекурсивний об'єкт, про який ви згадали), тож якщо у вас є memoize2
функція робити запам'ятовування (приймаючи функцію з двох аргументів - зробити її сумісною з вашою counter
), тоді ви можете написати:
let rec counter = memoize2 (fun init count ->
if init = 1 then count + 1 else
match init with
| Even value -> (counter (value/2) (1 + count))
| Odd value -> (counter ((3 * value) + 1) (count+1)) )
Такі рекурсивні посилання можуть бути небезпечними, тому F # вставляє кілька перевірок виконання. Це також дає попередження FS0040
повідомити вас про це, але в цьому випадкурекурсія правильна (проблема може виникнути, якщо під час ініціалізації звертався до рекурсивної посилання - тут ми використовуємо її лише пізніше, коли функція вже оголошена, тому все добре). Ви можете відключити попередження, додавши #nowarn "40"
.