2015-08-31 6 views
4

Можно ли проверить, была ли функция объявлена ​​как рекурсивная, то есть с let rec?Проверьте, объявлена ​​ли функция рекурсивной

У меня есть функция memoize, но она не работает с произвольными рекурсивными функциями. Я хотел бы дать ошибку, если пользователь называет ее такой функцией. (Не стесняйтесь сказать мне, если это плохой способ справиться с ошибками в F #)

+1

Что такое «произвольная рекурсивная функция»? Можете ли вы привести примеры кода того, о чем вы спрашиваете? – CoderDennis

ответ

5

Код F # скомпилирован в .NET Common Intermediate Language. Ключевое слово F # rec - это всего лишь намек на компилятор F #, который позволяет определить идентификатор, доступный в области действия функции. Поэтому я считаю, что во время выполнения нет возможности узнать, что функция объявила рекурсивной.

Однако вы можете использовать класс System.Diagnostic.StackTrace (https://msdn.microsoft.com/en-us/library/system.diagnostics.stacktrace.aspx) для получения и анализа кадров стека во время выполнения. Но доступ к информации стека имеет значительное влияние на производительность (я предполагаю, что ваша функция memoization предназначена для ускорения работы программы). Также информация стека может отличаться в версиях Debug и Release вашей программы, поскольку компилятор может выполнять оптимизацию.

+0

Не будет ли неудачный подход к трассировке стека неудачно для хвостовых рекурсивных функций (а что хуже - сбой только в режиме деблокирования по умолчанию)? Если рекурсия хвоста не оставляет достаточной информации о стеке, вы можете сказать, что делаете рекурсию? – scrwtp

+0

Наверное, да, а также, как я сказал, подход трассировки стека значительно повлияет на производительность – Petr

+0

Спасибо за объяснение. Приятно знать, что «isc» - это всего лишь подсказка компилятора (хотя информация могла быть сохранена где-то и найдена с использованием отражения). Решение StackTrace интересно. Я предполагаю, что из-за некруглого характера F # функция должна быть рекурсивной, если она появляется дважды в стеке вызовов. И нет, я бы не использовал это для оптимизации - мне в основном просто интересно и любопытно, и пытаюсь помочь себе лучше узнать и понять язык :) – MariusUt

2

Я не думаю, что это можно сделать разумным и всеобъемлющим образом.

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

Memoization торгует памятью для скорости. В большой системе вы можете не захотеть оплачивать затраты на замещение промежуточных результатов, если вы заботитесь только о последнем. Все эти словари складываются со временем.

Если вы, тем не менее, особенно заботитесь о мнимом рекурсивной функции, вы можете явно структурировать его таким образом, чтобы придать себя мемуаризации. См. linkedthreads.

Таким образом, я бы ответил, что функция memoize не должна касаться рекурсии вообще. Если пользователь хочет запоминать рекурсивную функцию, ему приходится понимать связанные с этим компромиссы и структурировать функцию таким образом, чтобы промежуточные вызовы могли быть замечены , если это то, что он требует.

Смежные вопросы