我会从高层次到你的具体问题:
Clojure(或 LISP)的一般工作原理
REPL 或 Read-Eval-Print 循环是 LISP 设计的核心:
-
阅读器将字符流转换为数据结构(称为阅读器表单)。
-
评估者收集读者表格并对其进行评估。
-
打印机发出评估器的结果。
因此,当您在 REPL 中输入文本时,它会通过每个步骤来处理您的输入并将输出返回到您的终端。
阅读器表单
首先是clojure 阅读器表单。这将非常简短,我鼓励您read 或观看(part 1,part 2)。
clojure 中的 symbol 是可以表示特定值(如变量)的形式。符号本身可以作为数据传递。它们类似于 c 中的指针,只是没有内存管理。
前面带有冒号的符号是关键字。关键字就像符号一样,除了关键字的值始终是它们本身 - 类似于字符串或数字。它们与 Ruby 的符号相同(也以冒号为前缀)。
表单前的引号告诉评估者保持数据结构不变:
user=> (list 1 2)
(1 2)
user=> '(1 2)
(1 2)
user=> (= (list 1 2) '(1 2))
true
虽然引用不仅仅适用于列表,但它主要用于列表,因为 clojure 的求值器通常会将列表作为类似函数的调用来执行。使用 ' 是引用宏的简写:
user=> (quote (1 2)) ; same as '(1 2)
(1 2)
引用基本上指定要返回的数据结构,而不是要执行的实际代码。所以你可以引用引用符号的符号。
user=> 'foo ; not defined earlier
foo
并且引用是递归的。所以里面的所有数据也都被引用了:
user=> '(foo bar)
(foo bar)
要在不引用的情况下获得(foo bar) 的行为,您可以对其进行评估:
user=> (eval '(foo bar)) ; Remember, foo and bar weren't defined yet.
CompilerException java.lang.RuntimeException: Unable to resolve symbol: foo in this context, compiling:(NO_SOURCE_PATH:1)
user=> (def foo identity)
#'user/foo
user=> (def bar 1)
#'user/bar
user=> (eval '(foo bar))
1
还有很多要引用的内容,但这超出了这个范围。
需要
至于 require 语句,我假设您以以下形式找到前者:
(ns my.namespace
(:require [clojure.set :as set]))
ns 是一个 macro,它将 :require 表达式转换为您描述的后一种形式:
(require '[clojure.set :as set])
还有一些命名空间工作。在 REPL 中询问 ns 的文档时描述了基础知识。
user=> (doc ns)
-------------------------
clojure.core/ns
([name docstring? attr-map? references*])
Macro
Sets *ns* to the namespace named by name (unevaluated), creating it
if needed. references can be zero or more of: (:refer-clojure ...)
(:require ...) (:use ...) (:import ...) (:load ...) (:gen-class)
with the syntax of refer-clojure/require/use/import/load/gen-class
respectively, except the arguments are unevaluated and need not be
quoted. (:gen-class ...), when supplied, defaults to :name
corresponding to the ns name, :main true, :impl-ns same as ns, and
:init-impl-ns true. All options of gen-class are
supported. The :gen-class directive is ignored when not
compiling. If :gen-class is not supplied, when compiled only an
nsname__init.class will be generated. If :refer-clojure is not used, a
default (refer 'clojure) is used. Use of ns is preferred to
individual calls to in-ns/require/use/import:
REPL 用法
一般情况下,不要在 REPL 中使用 ns,而只需使用 require 和 use 函数即可。但是在文件中,使用ns 宏来做这些事情。