Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/clojure/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Clojure 括号和括号之间有什么区别;“需要”吗;?_Clojure - Fatal编程技术网

Clojure 括号和括号之间有什么区别;“需要”吗;?

Clojure 括号和括号之间有什么区别;“需要”吗;?,clojure,Clojure,有一件事我有点困惑,那就是clojure require语句中括号和括号之间的区别。我想知道是否有人能给我解释一下。例如,它们做同样的事情: (ns sample.core (:gen-class) (:require clojure.set clojure.string)) (ns sample.core (:gen-class) (require clojure.set clojure.string)) (ns sample.core (:gen-class) (

有一件事我有点困惑,那就是clojure require语句中括号和括号之间的区别。我想知道是否有人能给我解释一下。例如,它们做同样的事情:

(ns sample.core
  (:gen-class)
  (:require clojure.set clojure.string))
(ns sample.core
  (:gen-class)
  (require clojure.set clojure.string))

(ns sample.core
  (:gen-class)
  (:require clojure.set clojure.string))

然而,这在repl中起作用

(require 'clojure.string 'clojure.test)
但在clj文件中失败

(ns sample.core
  (:gen-class)
  (:require 'clojure.string 'clojure.test))
...
Exception in thread "main" java.lang.Exception: lib names inside prefix lists must not contain periods
    at clojure.core$load_lib.doInvoke(core.clj:5359)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    ....
而这些人可能会做同样的事情:

(ns sample.core
  (:gen-class)
  (:require clojure.set clojure.string))
(ns sample.core
  (:gen-class)
  (require clojure.set clojure.string))

(ns sample.core
  (:gen-class)
  (:require clojure.set clojure.string))
总的来说,我不明白这一点。我了解使用、导入和要求。但我不理解“:”以及[]和'()等事物之间的区别。有人能以直观的方式阐明这个主题吗

TL;博士:

(ns sample.core (:gen-class) (:require clojure.set clojure.string)) 一般来说,最后一种形式是针对这一特殊要求的最佳实践



(需要“clojure.string”clojure.test)

也适用于clj文件-请尝试以下操作:

(ns sample.core (:gen-class)) (require 'clojure.string 'clojure.test) 工作,但这是一个意外-可能是因为

(name :require) => "require" (name 'require) => "require" (姓名:require) =>“需要” (名称“要求”) =>“需要” 文档化的语法是

(ns sample.core (:gen-class) (:require clojure.set clojure.string)) (ns)样品芯 (:gen类) (:require clojure.set clojure.string))
而且是唯一一个保证在未来不会崩溃的。这里的问题很微妙,如果不先了解一下宏,可能很难探究

宏操作语法的方式与函数操作值的方式相同。事实上,宏只是带有钩子的函数,钩子会在编译时对宏进行求值。它们被传递给您在源代码中看到的数据文本,并自上而下进行计算。让我们制作一个具有相同主体的函数和一个宏,这样您就可以看到不同之处:

(defmacro print-args-m [& args]
  (print "Your args:")
  (prn args))

(defn print-args-f [& args]
  (print "Your args:")
  (prn args))

(print-args-m (+ 1 2) (str "hello" " sir!"))

; Your args: ((+ 1 2) (str "hello" " sir!"))

(print-args-f (+ 1 2) (str "hello" " sir!"))

; Your args: (3 "hello sir!")
宏将被其返回值替换。您可以使用
macroexpand

(defmacro defmap [sym & args]
  `(def ~sym (hash-map ~@args))) ; I won't explain these crazy symbols here.
                                 ; There are plenty of good tutorials around

(macroexpand
  '(defmap people
     "Steve" {:age 53, :gender :male}
     "Agnes" {:age 7,  :gender :female}))

;  (def people
;    (clojure.core/hash-map
;      "Steve" {:age 53, :gender :male}
;      "Agnes" {:age 7, :gender :female}))
在这一点上,我应该解释一下,
导致下面的表单是
quote
d。这意味着编译器将读取表单,但不会执行表单或尝试解析符号等等。i、 e.
'conj
计算为符号,而
conj
计算为函数
(eval'conj)
相当于
(eval(quote conj))
相当于
conj

记住这一点,要知道,除非符号以某种方式神奇地导入到名称空间中,否则无法将其解析为名称空间。这就是
require
函数的作用。它接受符号并查找它们对应的名称空间,使它们在当前名称空间中可用

让我们看看
ns
宏扩展到什么:

(macroexpand
  '(ns sample.core
    (:require clojure.set clojure.string)))

;  (do
;    (clojure.core/in-ns 'sample.core)
;    (clojure.core/with-loading-context
;      (clojure.core/refer 'clojure.core)
;      (clojure.core/require 'clojure.set 'clojure.string)))
查看它如何为我们引用符号
clojure.set
clojure.string
?多方便啊!但是,当您使用
require
而不是
:require
时,有什么好处呢

(macroexpand
 '(ns sample.core
   (require clojure.set clojure.string)))

;  (do
;    (clojure.core/in-ns 'sample.core)
;    (clojure.core/with-loading-context
;      (clojure.core/refer 'clojure.core)
;      (clojure.core/require 'clojure.set 'clojure.string)))
似乎无论是谁编写了
ns
宏,都很好地让我们以两种方式执行,因为这个结果与以前完全相同。尼托

编辑:tvachon只使用
:require
是正确的,因为它是唯一官方支持的表单

但是括号是怎么回事

(macroexpand
  '(ns sample.core
    (:require [clojure.set] 
              [clojure.string])))

; (do
;  (clojure.core/in-ns 'sample.core)
;  (clojure.core/with-loading-context
;   (clojure.core/refer 'clojure.core)
;   (clojure.core/require '[clojure.set] '[clojure.string])))
事实证明,它们也会被引用,就像我们编写对
require
的独立调用一样

结果还表明,
ns
并不关心我们是给它提供列表(paren)还是向量(括号)。它只是将参数视为事物的序列。例如,这项工作:

(ns sample.core
  [:gen-class]
  [:require [clojure.set]
            [clojure.string]])
require
,正如amalloy在评论中指出的,对于向量和列表有不同的语义,所以不要混淆它们

最后,为什么下面的方法不起作用

(ns sample.core
  (:require 'clojure.string 'clojure.test))
好吧,因为
ns
为我们引用,这些符号被引用了两次,这在语义上不同于只被引用一次,也是纯粹的疯狂

conj    ; => #<core$conj clojure.core$conj@d62a05c>
'conj   ; => conj 
''conj  ; => (quote conj)
'''conj ; => (quote (quote conj))
conj;=>#
'conj;=>康杰
''conj;=>(引文conj)
''conj;=>(引文(引文conj))

我希望这会有所帮助,我绝对推荐学习如何编写宏。它们非常有趣。

Hm的可能副本,并不真正询问[]以及repl和clj代码之间的差异。“在Clojure源文件中,您应该始终使用ns子句来要求库-require应该只在repl中使用。”为什么?没有技术原因-完全是风格和可读性的原因。一致地使用
ns
可以确保其他程序员可以轻松地看到文件所需的名称空间,而无需深入查看整个文件。由于不需要手动转义表单,因此它也更简洁。
(:require(clojure.set)(clojure.string))
根本不起作用。这是一个no-op,因为您选择了两个已经是必需的名称空间,所以它看起来正好可以工作。在一些不存在的名称空间上尝试它:它以静默方式成功;在现存的名称空间上,它不做任何事情。此处使用参数表示前缀列表,如
(:require(clojure set string))
;您给出的语法仅适用于vectors.great答案,对于TDT引用,为+1,如果这是dj,为什么会起作用:
(ns image-test.core(:gen类)(:require(png extract)[clojure.string:as string])
(ns image-test.core(:gen类)(:require[png extract][clojure.string:as string]))
(ns sample.core
  (:require 'clojure.string 'clojure.test))
conj    ; => #<core$conj clojure.core$conj@d62a05c>
'conj   ; => conj 
''conj  ; => (quote conj)
'''conj ; => (quote (quote conj))