文档章节

clojure 新手指南(3)复杂表达式求值

凯奥斯
 凯奥斯
发布于 2013/07/03 11:28
字数 1247
阅读 727
收藏 5

 为了理解复杂的表达式和对它的操作,一个首要的前提就是理解”前缀表达式“。这可能会花费你一点时间来习惯它。不过我相信你会很快的爱上这种规则的。你想想,如果你要对多个值进行同一种运算,你只用写一个运算符在第一个值的最前面,而不是写多个运算符在中间。不信就看下面的例子:

普通:  1 + 2 + 3 + 4 + 5 + 6 + 8 + 9

前缀:  + 1 2 3 4 5 6 7 8 9
抛开前缀表示法不说,一个复杂表达式可以看出是一个单独的操作,或者是一组操作。它们既可以接收参数,也能向外输出,在整个表达式计算完成的时候返回计算结果。一句话,复杂的表达式可以做任何你想让它做的事情。让我们看一个非常简单的例子:
(+ 1 2)

在对这个式子求值前,我们先去看一看clojure在求值期间会做哪些工作:

首先,clojure会遇到左括号,表明这是一个列表(表达式的形式)的开始。这个列表包含了它要处理的所有东西。clojure永远会把左括号的第一个元素当做是一个操作符(这也是采用前缀表达式的原因),这种方式使得lisp方言语法异常的简单。在我们的例子中,操作符指的就是一个函数。(函数其实可以看出是针对其参数需要做哪些操作的说明)。当clojure遇到一个右括号,表明这个列表的结束。这种解析是递归的,因为列表中的元素依然可能是列表。这种表达方式还有另一个名字:S表达式。(lisp 的含义就是 list processor 即列表处理)。

S表达式看起来可能很直观,但对它的理解是非常非常重要的。这是学习一切lisp方言的基础。Clojure在执行函数(例如+)之前,首先会对其所有的参数进行顺序(从左到右)求值并返回自己的结果。然后函数会针对这些参数的返回结果进行相应的求值运算。返回最终的结果。

上面例子中,”+"是函数,参数都是数字字面值。我们说过字面值求值后返回自己。所以整个操作就是将“+”运用到1和2之上。得到的最终结果就是3。再考虑一下下面这个例子

(+ 2 (- 8 3))

上面例子稍微复杂了一点,因为第二个参数不是单纯的字面值。这个求值也非常简单,clojure在对第二个参数(- 8 3)进行求值时采取的依然是之前的策略,得到结果5。最终 "+"会作用在2和5之上,最终结果返回7。所以我们说这种解析方式是递归的。S表达式规则虽然简单,但是真的是变化无穷啊。

再来看一个例子(检测对前缀表达式的理解):

=>(- 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函数含义是一样。




© 著作权归作者所有

凯奥斯
粉丝 44
博文 51
码字总数 41388
作品 0
朝阳
程序员
私信 提问
加载中

评论(1)

Loli控
Loli控
V5~
clojure 新手指南(2)使用REPL求值

Clojure 拥有动态语言的所有好处。这意味着你可以在程序被加载后依然可以改变它,并且不用采取额外的步骤去编译代码。你既不用停止也不用重启正在运行的应用就可以让修改生效。这对于其他语言...

凯奥斯
2013/07/03
739
0
clojure 新手指南(4)代码保护

有时候,你可能需要防止一个表达式或者部分表达式被执行。这种就需要一种称为“代码保护”的技术。这项技术使用起来非常简单,就是在表达式前面加上一个单引号“ ‘ ”。clojure 遇到这种前缀...

凯奥斯
2013/07/03
377
0
clojure 新手指南(5):判断&基本类型

判断语句 在Clojure中,所有的语法规则最终都是S表达式。我们如何知道哪些是判断语句呢?这个很简单,clojure中(lisp习惯)有个规定:对于判断功能的函数,函数名后面都有一个“?”号。所以...

凯奥斯
2013/07/03
1K
1
clojure 新手指南(11):正则表达式

接着上篇,继续我们的时间和日期函数的探讨。我们可以定义一个函数,将一个日期字符串分成一个列表。列表元素分别为年、月、日、时、分、秒。为了完成这个字符串分割操作,我们使用“re-spli...

凯奥斯
2013/07/08
802
0
Clojure: 实现简单的数学表达式计算

我之前在知乎上回答了问题 按照运算符优先数法,画出算术表达式求值时,操作数栈和运算符栈的变化过程 。这次一方面也算是温故而知新,另一方面借此领略Clojure函数式编程之美。为了节省篇幅...

陈亦
2016/03/17
387
0

没有更多内容

加载失败,请刷新页面

加载更多

Docker常用命令小记

除了基本的<font color="blue">docker pull</font>、<font color="blue">docker image</font>、<font color="blue">docker ps</font>,还有一些命令及参数也很重要,在此记录下来避免遗忘。 ......

程序员欣宸
昨天
3
0
MAT使用-jvm内存溢出问题分析定位

1.MAT简介: MAT 全称 Eclipse Memory Analysis Tools 是一个分析 Java堆数据的专业工具,可以计算出内存中对象的实例数量、占用空间大小、引用关系等,看看是谁阻止了垃圾收集器的回收工作,...

xiaomin0322
昨天
4
0
内网和外网之间的通信(端口映射原理)

首先解释一下“内网”与“外网”的概念: 内网:即所说的局域网,比如学校的局域网,局域网内每台计算机的IP地址在本局域网内具有互异性,是不可重复的。但两个局域网内的内网IP可以有相同的...

Jack088
昨天
5
0
3.深入jvm内核-原理、诊断与优化-4. GC算法和种类

一、GC算法和种类 GC的概念 GC算法 引用计数法 标记清除 标记压缩 复制算法 可触及性 Stop-The-World GC的对象是堆空间和永久区 引用计数法 老牌垃圾回收算法 通过引用计算来回收垃圾 使用者...

hexiaoming123
昨天
4
0
MySQL中的哈希索引

Memory中的哈希索引 哈希索引是基于哈希表实现的,只有精确匹配索引所有列的查询才有效。对于每一行数据,存储引擎都会对所有的索引列计算一个哈希码,哈希码是一个较小的值,并且不同键值的...

我的眼里只有眼屎
昨天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部