Ответ 1
Компилятор С# никогда не будет использовать префикс tail
.
F # будет делать это, если вызов находится в хвостовом положении. Это зависит от того, как вы пересекаете дерево, подходит ли хвостовая рекурсия.
В вашем коде нет ничего в положении хвоста. Причина заключается в использовании тройного оператора. Если код переписан для использования операторов if
с возвратом каждой ветки, то вызов parent.root
будет находиться в хвостовом положении.
В плане оптимизации компилятор (F # или IronScheme) обычно преобразует хвостовые рекурсивные вызовы в циклы while (true) { ... }
. Это делается, поскольку он удаляет как хвостовой вызов, так и необходимость повторного вызова метода.
Поэтому, если С# было разрешено испускать хвостовые вызовы (что это не так), это, скорее всего, будет преобразовано из:
public Tree root
{
get
{
if (parent == null) return this;
else return parent.root; // now in tail position
}
}
(только гость)
public Tree root
{
get
{
Tree temp = this;
while (true)
{
if (temp.parent == null)
{
return temp;
}
temp = temp.parent;
}
}
}
F # и IronScheme выполняют одно и то же преобразование. Это называется tail call elimination
(TCE). И да, это будет немного быстрее, чем версия С#. (Я проверил это с помощью microbenchmarking fib
на С#, F # и IronScheme)