在clojure中,函数内部定义的var在函数外部仍然可以访问,为什么?
在Clojure REPL中:在clojure中,函数内部定义的var在函数外部仍然可以访问,为什么?,clojure,scheme,Clojure,Scheme,在Clojure REPL中: user> (defn add [x y] (def foo :defined-inside) (+ x y)) #'user/add user> foo #object[clojure.lang.Var$Unbound 0x63a0ad69 "Unbound: #'user/foo"] user> (add 1 1) 2 user> foo :defined-inside 显然,我认为foo不应该在add之外访问,为什么Clojure允
user> (defn add [x y] (def foo :defined-inside) (+ x y))
#'user/add
user> foo
#object[clojure.lang.Var$Unbound 0x63a0ad69 "Unbound: #'user/foo"]
user> (add 1 1)
2
user> foo
:defined-inside
显然,我认为
foo
不应该在add
之外访问,为什么Clojure允许这样做,这与其他lisp(例如scheme)不同?def
在Clojure中始终是全局的,与其他一些lisp不同
要在函数中创建本地符号绑定,请使用
让
def
在Clojure中始终是全局的,这与其他一些Lisp不同
要在函数中创建本地符号绑定,请在Clojure中使用
let
您可以使用let
定义本地变量:
(defn add [x y]
(let [foo :defined-inside]
(+ x y)))
它甚至可以用于本地功能:
(defn add [x y]
(let [foo (fn [x y] (+ x y))]
(foo x y)))
但是对于相互递归函数,您需要使用letfn
:
(defn is-odd? [n]
(letfn [(is-even? [n]
(if (zero? n)
true
(is-odd? (dec n))))
(is-odd? [n]
(if (zero? n)
false
(is-even? (dec n))))]
(is-odd? n)))
在Clojure中,您可以使用
let
定义本地变量:
(defn add [x y]
(let [foo :defined-inside]
(+ x y)))
它甚至可以用于本地功能:
(defn add [x y]
(let [foo (fn [x y] (+ x y))]
(foo x y)))
但是对于相互递归函数,您需要使用letfn
:
(defn is-odd? [n]
(letfn [(is-even? [n]
(if (zero? n)
true
(is-odd? (dec n))))
(is-odd? [n]
(if (zero? n)
false
(is-even? (dec n))))]
(is-odd? n)))
当我想通过调用函数在全局变量中创建绑定时,函数内部的Def非常有用
(defn initialize-browser []
(def browser (run-browser)))
例如,我使用此模式运行带有selenium的浏览器。
我可以轻松控制浏览器的状态。
如果我不想运行浏览器,我不会调用该函数。当我想运行和处理浏览器时,我只调用此函数一次,并由其他函数处理。当我想通过调用函数在全局变量中创建绑定时,函数内部的Def非常有用
(defn initialize-browser []
(def browser (run-browser)))
例如,我使用此模式运行带有selenium的浏览器。
我可以轻松控制浏览器的状态。
如果我不想运行浏览器,我不会调用该函数。当我想运行和处理浏览器时,我只调用此函数一次,然后由其他函数处理。other lisp。。。CL
defparameter
,defun
,defvar
创建顶级绑定。Scheme是唯一一个具有这种奇怪功能的方案,即lambda
内部的define
由lambda
宏处理(并重写为letrec
,最终变成lambda
表单),而顶层的define
则由它自己的宏处理。@Sylvester对我来说,我认为这是一个坏主意,因为它会污染全局环境,Scheme是正确的选择。如果您想要一个局部变量或函数,您永远不会使用def
,这与Common Lisp一样。它与Scheme中的相同,但混淆较少(因为您可能会有这样的印象,define
与let
中的顶层工作相同,但它是由实现的两个完全不同的部分完成的,除了名称冲突之外,它们彼此无关)其他lisp。。。CLdefparameter
,defun
,defvar
创建顶级绑定。Scheme是唯一一个具有这种奇怪功能的方案,即lambda
内部的define
由lambda
宏处理(并重写为letrec
,最终变成lambda
表单),而顶层的define
则由它自己的宏处理。@Sylvester对我来说,我认为这是一个坏主意,因为它会污染全局环境,Scheme是正确的选择。如果您想要一个局部变量或函数,您永远不会使用def
,这与Common Lisp一样。这与Scheme中的相同,但混淆较少(因为您可能会有这样的印象,define
与let
中的顶层工作相同,但它是由实现的两个完全不同的部分完成的,除了名称冲突之外,它们之间没有任何关系)为什么Clojure是以这种方式设计的,有什么原因吗?对我来说,我认为这是一个坏主意,因为它会污染全球环境。因为Clojure喜欢给你足够的绳子来吊死自己。有时使用各种奇怪的副作用要容易得多;你必须清楚地表明你的意思,但如果你愿意,上帝保佑,里奇·希基会让你这么做的。为什么Clojure是这样设计的,有什么原因吗?对我来说,我认为这是一个坏主意,因为它会污染全球环境。因为Clojure喜欢给你足够的绳子来吊死自己。有时使用各种奇怪的副作用要容易得多;你必须清楚地表明你的意思,但如果你愿意,上帝保佑,里奇·希基会让你这么做的。