在 Scheme 中,我可以这样做:
(define (adder)
(define (one) 1)
(define (two) 2)
(+ (one) (two)))
在调用adder
时调用3
结果one
会产生错误,因为one
仅在adder
范围内可见。
在 Clojure 中,如果我做类似的事情
(defn adder []
(defn one [] 1)
(defn two [] 2)
(+ (one) (two)))
one
和two
将污染我的命名空间,因为defn
在内部使用def
,这会在当前命名空间中创建绑定。
是否有一个函数/宏在本地范围内创建命名函数?
我的问题的原因是我习惯了Scheme的工作方式。以这种方式命名我的本地函数通常会使我的代码更具可读性。
答案 0 :(得分:13)
尝试letfn:
获取函数specs和body的向量,并生成一组 函数与其名称的绑定。所有名称都可用 在函数的所有定义中,以及正文。
(defn adder []
(letfn [(one [] 1)
(two [] 2)]
(+ (one) (two))))
答案 1 :(得分:9)
除了Alex的出色答案外,任何fn
都可以命名。
(defn adder []
(let [one (fn [] 1)
two (fn [] (+ (one) (one)))]
(+ (one) (two))))
如果您已经有let
块,这将非常有用。
如果fn
引用自身,则需要自己的名称
(defn silly []
(let [constant 5
thing (fn thong
([a] (+ a constant))
([] (inc (thong constant))))]
(* (thing) (thing))))
fn
绑定的名称不必与其自身所知的名称相同。
答案 2 :(得分:1)
如果您想要一个当前命名空间可见但其他命名空间不可见的函数 - 您可以使用defn-
<强> DEFN - 强>
宏
用法:( defn-name&amp; decls)
与defn相同,产生非公开def
来自http://clojuredocs.org/clojure_core/clojure.core/defn-
user=> (ns test)
nil
test=> (defn- foo [] "World!")
#'test/foo
test=> (defn bar [] (str "Hello " (foo)))
#'test/bar
test=> (foo)
"World!"
test=> (bar)
"Hello World!"
test=> (ns playground)
nil
playground=> (test/bar)
"Hello World!"
;; Error will be thrown
;; var: #'test/foo is not public
playground=> (test/foo)