Ответ 1
Варианты С# и F # имеют важное различие: функция С# не имеет никаких параметров, но версия F # имеет один параметр типа unit
. Это значение unit
- это то, что отображается как ldnull
(поскольку null
используется как представление единственного значения unit
, ()
).
Если вы должны были перевести вторую функцию на С#, она выглядела бы так:
T ResultOfFunc<T>( Func<Unit, T> f ) {
return f( null );
}
Что касается команды .tail
- это так называемая "оптимизация хвостового вызова".
Во время обычного вызова функции обратный адрес попадает в стек (стек процессора), а затем вызывается функция. Когда функция выполняется, она выполняет команду "return", которая выталкивает обратный адрес из стека и передает туда контроль.
Однако, когда функция A
вызывает функцию B
, а затем сразу возвращает функцию B
возвращаемое значение, не делая ничего другого, CPU может пропустить нажатие дополнительного адреса возврата в стеке и выполнить "переход" на B
вместо "вызова". Таким образом, когда B
выполняет команду "return", CPU выдает адрес возврата из стека, и этот адрес указывает не на A
, а на того, кто первым вызвал A
.
Другой способ подумать об этом: function A
вызывает функцию B
не перед возвратом, а вместо возвращения, и, таким образом, делегирует честь вернуться к B
.
Таким образом, эта магическая техника позволяет нам делать вызов, не потребляя пятно в стеке, а это означает, что вы можете выполнять произвольно много таких вызовов, не рискуя переполнением стека. Это очень важно в функциональном программировании, поскольку оно позволяет эффективно внедрять рекурсивные алгоритмы.
Он называется "tail call", потому что вызов B
происходит, так сказать, в хвосте A
.