在clojure中,函数内部定义的var在函数外部仍然可以访问,为什么?

在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允

在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允许这样做,这与其他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。。。CL
defparameter
defun
defvar
创建顶级绑定。Scheme是唯一一个具有这种奇怪功能的方案,即
lambda
内部的
define
lambda
宏处理(并重写为
letrec
,最终变成
lambda
表单),而顶层的
define
则由它自己的宏处理。@Sylvester对我来说,我认为这是一个坏主意,因为它会污染全局环境,Scheme是正确的选择。如果您想要一个局部变量或函数,您永远不会使用
def
,这与Common Lisp一样。这与Scheme中的相同,但混淆较少(因为您可能会有这样的印象,
define
let
中的顶层工作相同,但它是由实现的两个完全不同的部分完成的,除了名称冲突之外,它们之间没有任何关系)为什么Clojure是以这种方式设计的,有什么原因吗?对我来说,我认为这是一个坏主意,因为它会污染全球环境。因为Clojure喜欢给你足够的绳子来吊死自己。有时使用各种奇怪的副作用要容易得多;你必须清楚地表明你的意思,但如果你愿意,上帝保佑,里奇·希基会让你这么做的。为什么Clojure是这样设计的,有什么原因吗?对我来说,我认为这是一个坏主意,因为它会污染全球环境。因为Clojure喜欢给你足够的绳子来吊死自己。有时使用各种奇怪的副作用要容易得多;你必须清楚地表明你的意思,但如果你愿意,上帝保佑,里奇·希基会让你这么做的。