Какова причина маркировки рекурсивной функции как rec в F #?
Я не уверен, что это глупый вопрос, но я прошел учебник, который поставляется с VS 2010, и существует такая функция:
let rec factorial n = if n=0 then 1 else n * factorial (n-1)
Какова причина, по которой эта рекурсивная функция должна быть отмечена ключевым словом rec?
Это значит, что компилятор уверен в том, что он рекурсивный, поэтому можно сделать некоторые оптимизации?
Что произойдет, если вы его исключите?
Ответы
Ответ 1
Это может быть поучительно:
let Main() =
let f(x) =
printfn "original f: %d" x
let f(x) =
//let rec f(x) =
printfn "entered new f: %d" x
if x > 0 then
f(x-1)
else
printfn "done"
f(3)
Main()
Что печатает
entered new f: 3
original f: 2
Теперь, если мы прокомментируем let
и раскомментируем let rec
, тогда он печатает
entered new f: 3
entered new f: 2
entered new f: 1
entered new f: 0
done
Итак, с этой точки зрения, это просто привязка имени; let rec
немедленно помещает идентификатор в область видимости (в этом примере затеняет предыдущий f
), тогда как let
помещает идентификатор в область видимости только после определения его тела.
Мотивация правила основывается на взаимодействиях с типом вывода.
Ответ 2
По словам Криса Смита (работает над командой F #) -
Он должен сообщить системе вывода типа, чтобы позволить использовать эту функцию как часть процесса вывода типа. rec позволяет вызывать функцию до того, как система вывода типа определит тип функции
Ответ 3
Согласно MSDN, это только синтаксическая необходимость:
Рекурсивные функции, функции, которые называют себя, идентифицированы явно на языке F #. Эта делает идентификатор, который определенных в объеме функция.
http://msdn.microsoft.com/en-us/library/dd233232.aspx
Ответ 4
Необходимо, чтобы функция могла быть рекурсивной. Функция не rec
знает только о привязках в том месте, где она была определена, а не после (поэтому она не знает о себе).
Ответ 5
Какова причина, по которой эта рекурсивная функция должна быть отмечена ключевым словом rec?
Чтобы сообщить компилятору, что любое использование имени функции внутри тела функции ссылается на него рекурсивно, а не на ранее определенное значение с тем же именем.
Это значит, что компилятор уверен в том, что он рекурсивный, поэтому можно сделать некоторые оптимизации?
Нет.
Что произойдет, если вы его исключите?
Вы теряете способность функции, которую вы определяете, ссылаться на себя в своем теле функции и получать возможность ссылаться на ранее определенные значения с тем же именем.