clojure 新手指南(3)複雜表達式求值

 爲了理解複雜的表達式和對它的操做,一個首要的前提就是理解」前綴表達式「。這可能會花費你一點時間來習慣它。不過我相信你會很快的愛上這種規則的。你想一想,若是你要對多個值進行同一種運算,你只用寫一個運算符在第一個值的最前面,而不是寫多個運算符在中間。不信就看下面的例子: 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函數含義是同樣。
相關文章
相關標籤/搜索