Совершенно независимо от конкретной c семантики Scheme & CL (которая, по крайней мере для CL, довольно сложна и может варьироваться различными способами), я думаю, вы не понимаете, когда вызываются функции. Я рассмотрю пример CL и приму совершенно наивную программу, которая оценивает определения, которые вы даете, по порядку. Программа, подобная этой:
(defun naively-evaluate-file (f)
(let ((*package* *package*))
(with-open-file (in f)
(loop for form = (read in nil in)
until (eql form in)
collect (eval form)))))
Итак, хорошо, что делает эта функция, когда она просматривает ваш файл?
- Она видит форму
(defun function-defined-early () (function-defined-later))
и оценивает ее. Оценка формы defun
определяет функцию function-defined-early
и эту функцию, при вызове вызовет function-defined-later
, которая еще не определена. Но функция не вызывается, поэтому проблем нет. - Он видит
(defun function-defined-later () 1)
и оценивает ее, что определяет (но не вызывает) function-defined-later
. - Он видит
(print (function-defined-early))
, который вызывает function-defined-early
и, следовательно, function-defined-later
, оба из которых определены, и печатает результат.
Таким образом, вы можете видеть, что на самом деле ни одна функция не вызывается до того, как она определена , Функции определены перед определением вызываемых ими функций, но эти функции не вызываются во время определения.
Кроме того, такое определение с прямой ссылкой почти неизбежно, когда определение функций, если вы хотите разрешить рекурсию на языке. Рассмотрим это ужасное определение факториальной функции:
(defun fact (n)
(if (= n 1)
1
(* n (fact (1- n)))))
Хорошо, когда система оценивает это определение, чтобы определить fact
, она увидит вызов fact
, который ... еще не определен , Что ж, возможно, вы могли бы сделать это в специальном случае (и компиляторы CL могут это делать): предположим, что этот вызов, по сути, является вызовом определяемой вами функции.
Таким образом, вы можете использовать специальный случай функции, которые только рекурсивно вызывают сами . Но как только у вас есть две или более функции, которые рекурсивно вызывают друг друга , вы не можете избежать одной из них в точке, где она определена (не вызывается!), Ссылаясь на некоторые еще не -определенная функция. Так что проблема прямой ссылки во время определения практически неизбежна.
(Ну, на самом деле вы могли бы избежать этого: вы могли бы сделать всю свою рекурсию с помощью Y комбинатора или чего-то еще, но пока это интересно в теории (и дать непонятные ответы на домашние вопросы), никто не хочет делать это на практике.)