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函数含义是同样。
相关文章
相关标签/搜索