爲了理解複雜的表達式和對它的操做,一個首要的前提就是理解」前綴表達式「。這可能會花費你一點時間來習慣它。不過我相信你會很快的愛上這種規則的。你想一想,若是你要對多個值進行同一種運算,你只用寫一個運算符在第一個值的最前面,而不是寫多個運算符在中間。不信就看下面的例子: python
普通: 1 + 2 + 3 + 4 + 5 + 6 + 8 + 9 前綴: + 1 2 3 4 5 6 7 8 9拋開前綴表示法不說,一個複雜表達式能夠看出是一個單獨的操做,或者是一組操做。它們既能夠接收參數,也能向外輸出,在整個表達式計算完成的時候返回計算結果。一句話,複雜的表達式能夠作任何你想讓它作的事情。讓咱們看一個很是簡單的例子:
(+ 1 2)
在對這個式子求值前,咱們先去看一看clojure在求值期間會作哪些工做: shell
首先,clojure會遇到左括號,代表這是一個列表(表達式的形式)的開始。這個列表包含了它要處理的全部東西。clojure永遠會把左括號的第一個元素當作是一個操做符(這也是採用前綴表達式的緣由),這種方式使得lisp方言語法異常的簡單。在咱們的例子中,操做符指的就是一個函數。(函數其實能夠看出是針對其參數須要作哪些操做的說明)。當clojure遇到一個右括號,代表這個列表的結束。這種解析是遞歸的,由於列表中的元素依然多是列表。這種表達方式還有另外一個名字:S表達式。(lisp 的含義就是 list processor 即列表處理)。 app
S表達式看起來可能很直觀,但對它的理解是很是很是重要的。這是學習一切lisp方言的基礎。Clojure在執行函數(例如+)以前,首先會對其全部的參數進行順序(從左到右)求值並返回本身的結果。而後函數會針對這些參數的返回結果進行相應的求值運算。返回最終的結果。 函數
上面例子中,」+"是函數,參數都是數字字面值。咱們說過字面值求值後返回本身。因此整個操做就是將「+」運用到1和2之上。獲得的最終結果就是3。再考慮一下下面這個例子 學習
(+ 2 (- 8 3))
上面例子稍微複雜了一點,由於第二個參數不是單純的字面值。這個求值也很是簡單,clojure在對第二個參數(- 8 3)進行求值時採起的依然是以前的策略,獲得結果5。最終 "+"會做用在2和5之上,最終結果返回7。因此咱們說這種解析方式是遞歸的。S表達式規則雖然簡單,可是真的是變化多端啊。 spa
再來看一個例子(檢測對前綴表達式的理解): code
=>(- 8 3 2 1 -6 34 12 4 2 6 4 -23 12 4) -47
瞭解完上面,接下來作點啥呢?運行點例子也許是個好主意,可是還有更好的方法。讓咱們看一看內置函數的源碼來了解一下。查看某個函數的源碼很簡單,仍是調用函數來作。咱們會使用一個名爲「source」的函數:(source 【函數名】) 遞歸
讓咱們查看函數'-'(減號)的源碼 源碼
=>(source -) ;;依然是S表達式 (defn - "If no ys are supplied, returns the negation of x, else subtracts the ys from x and returns the result." {:inline (fn [& args] `(. clojure.lang.Numbers (minus ~ @args))) :inline-arities #{1 2} :added "1.0"} ([x] (. clojure.lang.Numbers (minus x))) ([x y] (. clojure.lang.Numbers (minus x y))) ([x y & more] (reduce - (- x y) more))) nil這個比預想的要多的多了,一個減號竟然有這麼多代碼量。如今不用擔憂不理解上面的代碼。由於這裏麪包含了不少未知的知識。咱們只用知道一點是,咱們的」-「能夠操做任意個參數的能力,而這一切歸功一個叫作」reduce「的函數。咱們不用去調用」reduce「的源碼,只用看看相關描述便可。咱們可使用」doc「函數:
=>(doc reduce) ------------------------- clojure.core/reduce ([f coll] [f val coll]) f should be a function of 2 arguments. If val is not supplied, returns the result of applying f to the first 2 items in coll, then applying f to that result and the 3rd item, etc. If coll contains no items, f must accept no arguments as well, and reduce returns the result of calling f with no arguments. If coll has only 1 item, it is returned and f is not called. If val is supplied, returns the result of applying f to val and the first item in coll, then applying f to that result and the 2nd item, etc. If coll contains no items, returns val and f is not called. nil這裏的reduce和python中的reduce函數含義是同樣。