標籤:

clojure中 x x #x 他們之間的關係一直很暈 能給一些應用場景例子嗎?

例如:

(def x 5)

在後面 什麼情況下 使用 "x 什麼情況下使用#"x 他們之間的關係是什麼


不需要完全理解"x和#"x,這兩者大部分情況下只有寫宏會用到。而寫宏的第一條原則就是沒事兒別寫宏。等到能看懂的時候自然就能看懂了。

"x

單引號"叫做quote macro 引用,等於quote函數,即 "x 和 (quote x)是等價的,用於阻止求值

(1 2 3) ; error, 1 is not a function
"(1 2 3) ; ok, return list (1 2 3)
(quote (1 2 3)) ; same as above

#"x

叫做var macro,可以拆作兩部分,井號#叫做dispatch macro,當#出現在其他token前面時,表示告訴Clojure Reader,你需要去另外一張表裡找後面符號的意思。

Clojure Reader的任務是讀入代碼文本,解析,生成編譯器所需的結果;通常會在默認的reader table里查找特殊符號含義。比如雙引號是字元串,加上#就變成regex了。

在這裡#出現後,單引號"的意義就與前文不同,#"等同於var函數

user=&> (def one 1) ; ok, `one` is 1 now
#"user/one
user=&> one ; eval `one`
1
user=&> #"one
#"user/one ; return variable token itself
user=&> (var one)
#"user/one ; same as above


理解好三點,

1,Clojure里的符號(Symbol)也是一種數據類型,quote某一個symbol後本質是想獲得符號本身,而表現出來就是阻止其求值。

2,Reader Macro

3,var屬於Clojure里四種引用類型(referential type)的一種,作用於線程本地(thread local),目前你就只需把var當成一個值的容器來想像。

舉例,

(def x 10)的意思是: 在當前命名空間下,將符號x與一個根綁定(root binding)為10的var進行映射,解析符號x就是獲得符號x所映射的var中綁定的值10,所以你在repl中敲入x,返回的10。你也可以使用(var x)或#"x獲得var引用本身。

特別注意,var不是variable(變數),Clojure不會對內存位置里的值直接進行修改。


@z展新 把原理解釋的比較清楚了,但是沒有介紹使用場景,我這裡補充下。

當我們在 Clojure 裡面執行

(def foo 10)

時,JVM 的內存裡面大概是這樣的:

Symbol 是種數據類型,和 int、String 一樣,它是構成 Lisp 程序的基本單元,Symbol 這種類型只出現在 Lisp 這類能進行 meta-programming 的語言里,具體到 Lisp 裡面就是 macro 了,Clojure 的 macro 通過在編譯時操作 symbol,產生運行時的代碼,這是其威力所在,其他語言像 Java、python 沒有這種能力。

Var 是 Clojure 裡面的一種引用類型,大多數情況下我們需要的是 var 所代表的值,但是如果我們像獲取 var 的一些 meta 信息,就需要 var 本身了。比如:

user=&> (def ^{ :debug true } five 5)
#"user/five
user=&> (meta #"five)
{:ns #&, :name five, :column 1, :debug true, :line 1, :file "NO_SOURCE_PATH"}


"x = (quote x)

#"x = (var x)

quote 和 var 都是 special form

(quote x) 是防止對 x 求值

(var x) 是返回符號 x 指向的變數對象, 前提是 x 必須是符號, 不然會出錯

ClojureDocs 的例子:

(var 1)
;CompilerException java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.Symbol, compiling:(NO_SOURCE_PATH:1:1)


推薦閱讀:

Lisp 解釋器?
如何寫 Lisp 解釋器?
一個編程語言能否成功的關鍵之處?
Lisp可以完成哪些其它語言難以實現的功能?最好能夠舉一些例子
函數式語言中如何實現while true?

TAG:Lisp | Clojure |