Специальная форма def
создает объект Var , идентифицируемый символом, указанным в качестве первого аргумента.Идентификация создается путем связывания данного символа с Var в карте, называемой пространством имен.
Var содержит ссылку на некоторое значение , которое может быть выражено (среди прочих):
как постоянная форма, которая всегда оценивается как ее собственное значение :
(def x 1)
x
; => 1 ; x holds a reference to a number 1
как форма функции, который сначала оценивается как его результирующее значение :
(def x (+ 2 2))
x
; => 4 ; x holds a reference to a number 4
как форма метода Java, которая сначала оценивается какрезультирующее значение :
(def x (System/currentTimeMillis))
x
; => 1417811438904
; x holds a reference to a number 1417811438904
x
; => 1417811438904
; still the same number!
в виде лямбда-формы (анонимная функция), которая сначала оценивается как объект функции :
(def x (fn [] (System/currentTimeMillis)))
x
; => #<user$x user$x@4c2b1826>
(x) ; function form, function evaluated
; => 1417811438904
(x) ; function form, function evaluated
; => 1417812565866
Существует простое правило для всего вышеперечисленного.В случае специальной формы def
S-выражение, заданное в качестве второго аргумента, рекурсивно оценивается до создания привязки , поэтому результирующий Var связывается с результатом этой оценки.
Даже fn
вычисляется ранее, но его результирующее значение является функциональным объектом, который содержит код.Этот код будет выполняться (и оцениваться) каждый раз, когда вызывается функция .Вот почему есть разные результаты.
Макрос defn
похож на def
, но внутри он создает анонимную функцию и затем привязывает к ней объект Var.Его второй аргумент становится телом этой функции, и он не оценивается "обычным" способом.Можно также сказать, что он оценивается, но как лямбда-форма - результатом оценки является функциональный объект, а не результат какого-то мгновенного вычисления.
Итак, запись:
(defn fun [] 1)
Синоним:
(def fun (fn [] 1))