- 浏览: 83091 次
- 性别:
- 来自: 成都
最新评论
-
荆人七十:
谢谢分享~
在eclipse上面搭建Clojure开发运行环境 -
lanily:
楼主,跟你学clojure了,我想请教一个问题:本人事先是用j ...
Clojure细节之form和special form的区别 -
Dead_knight:
http://code.google.com/p/clojur ...
practical_clojure chapter3 控制程序流(未完) -
石建武:
谢谢。提供的离线包。但如果通过‘install new’方式, ...
在eclipse上面搭建Clojure开发运行环境 -
songry:
linkerlin 写道标题里面的 未完 ,啥时候能去掉?可以 ...
practical_clojure chapter3 控制程序流(未完)
注:本文基于jdk1.6,clojure1.2
比较操作
等于=
clojure中的等于和java中的equals方法类似,但是clojure中的=还能够作用于nil、数字和集合上面。看看例子:
user> (= 3) true user> (= 5 5) true user> (= "a" "a") true user> (= '(7 8.0 9) [7 8.0 9]) true user> (= '(7 8.0 9) [7 8 9]) true user> (= (java.lang.String. "nice") (java.lang.String. "nice")) true
从上面的例子来看,=应该是做的值比较,那我们再来验证一下看看:
user> (= (java.lang.String. "nice") (java.lang.String. "nice")) true user> (= 1.25 5/4) true user> (= 8.00M 8) false user> (= 8.00 8) true user> (= 127 0x7f) true user> (= (java.lang.Float. 127.0) 127.0) true
除了声明为BigDecimal的数字之外,其他的都成功了。让我们来看看源码:
user> (source =) (defn = "Equality. Returns true if x equals y, false if not. Same as Java x.equals(y) except it also works for nil, and compares numbers and collections in a type-independent manner. Clojure's immutable data structures define equals() (and thus =) as a value, not an identity, comparison." {:inline (fn [x y] `(. clojure.lang.Util equiv ~x ~y)) :inline-arities #{2} :added "1.0"} ([x] true) ([x y] (clojure.lang.Util/equiv x y)) ([x y & more] (if (= x y) (if (next more) (recur y (first more) (next more)) (= y (first more))) false)))
从上面源码中我们可以看出,如果=函数的传入参数为1个时,会直接返回true; 即使参数是nil也是如此:
user> (= nil) true
传入参数为2个时,会调用clojure.lang.Util类的equiv静态方法,这个方法首先判断两个参数的引用是否相等,
如果引用相等,则返回true;然后判断两个参数是否都是Number的子类,如果是,则调用Number的equiv方法
来判断两个参数的值是否相等,如果相等,则返回true;接着判断其中一个参数是否IPersistentCollection的子类
,如果是,则调用其equiv方法并返回结果;如果此时还没有返回,就会直接调用参数的equals方法来做比较了。
当传入参数大于2时,按惯例,必定是要进行递归了。但是我们注意到,这儿的递归和之前数学运算中的递归
有所不同,这儿采用了recur特殊form,这是个什么东西?实际上,这是clojure的显式尾递归标识。
众所周知,递归调用的一般形式是逐层嵌套调用函数直至满足某个条件后返回结果并逐层向外传递直至到达最
外层得出最终结果,而每一次递归调用时都会往本地方法栈中压入一个栈帧,如果递归的层数够多,毫无疑问,
stackoverflow。但是很多递归实际上只需要最后一次执行的结果,递归过程中产生的结果是无用的,在这种情况
下,就可以采用尾递归。尾递归跟一般递归的不同在于,每次递归执行的方法会替换上次执行的栈帧,换句话说,
每次执行的递归操作除了将参数传递给下一次递归之外,方法体本身是没有在内存中保留的;当执行到最后一次
递归操作时,它会把结果直接返回给最外层的调用者,而不是逐层上报。这在理论上是可以进行“无限”递归的。
让我们看看当前的情况,这是一个典型的尾递归场景,不管中间运行多少次的结果为true,只要某一次运行的
结果为false,就结束递归,将false传回给调用者。如果执行到最后一次递归仍然返回true,那么直接将这个true
返回给调用者就可以了,因为如果递归中途有false就根本执行不到最后一步递归,已经执行到了最后这一步,就代表
前面的所有结果都为true。
我们再看看recur的用法,其实在一般情况下,recur都跟loop配对使用,loop声明递归点并建立临时绑定,recur
进行递归操作;而在当前的例子中,recur调用的尾递归实际上是对应的[x y & more],注意它们的参数匹配。如果
我们采用loop来重构,那么它的形式将是:(省略了说明性文字和元数据)
(defn = ([x] true) ([x y] (clojure.lang.Util/equiv x y)) ([x y & more] (loop [one x two y others more] (if (= one two) (if (next others) (recur two (first others) (next others)) (= two (first others))) false))))
这样子结构是否要清晰一些呢,只要执行到recur,就跳转到loop处开始执行。
数值等于==
==的功能和=相似,不过==只用于比较数字的值:
user> (== 2 2.00000) true
如果我们采用非Number类型的参数,就会抛出类型转换异常:
user> (== '(1 3) [1 3]) clojure.lang.PersistentList cannot be cast to java.lang.Number [Thrown class java.lang.ClassCastException]
让我们看看源码:
user> (source ==) (defn == "Returns non-nil if nums all have the same value, otherwise false" {:inline (fn [x y] `(. clojure.lang.Numbers (equiv ~x ~y))) :inline-arities #{2} :added "1.0"} ([x] true) ([x y] (. clojure.lang.Numbers (equiv x y))) ([x y & more] (if (== x y) (if (next more) (recur y (first more) (next more)) (== y (first more))) false)))
很明显,这个源码的结构和=的几乎是一模一样,唯一的区别是在做二元判断时直接调用了clojure.lang.Numbers
的equiv方法,这就决定了==只能用于数字的比较,因为多元判断同样是递归了二元判断。
不过我们也注意到,当参数只有一个的时候,实际上是没有类型判断的:
user> (== nil) true
但这个应该没什么实际用途,哈哈。
不等于not=
not=的本质其实就是对=判断的结果取反而已,所以=支持什么类型,not=就支持什么类型:
user> (not= 3) false user> (not= 5 3) true user> (not= '(7 8 9) [7 8 9]) false user> (not= 8M 8) false user> (not= 8.0M 8) true
源码一下就暴露出其本质了:
user> (source not=) (defn not= "Same as (not (= obj1 obj2))" {:tag Boolean :added "1.0"} ([x] false) ([x y] (not (= x y))) ([x y & more] (not (apply = x y more))))
不过这儿跟之前不同的地方在于,没有用递归(当然=的源码中还是有递归的),而是直接采用了apply。apply的
作用其实很好理解,它接收两部分的参数,第一部分是一个函数,在当前的例子中是=函数;第二部分是数个参数,这
个参数的数量跟第一部分的参数函数有关,比如:在当前例子中,=函数可以传入三个参数,那么第二部分我们就传入
三个参数x、y和一个集合more。执行时apply会首先把第二部分的参数传入第一部分的函数中,在当前例子,就是把
x、y和集合more中的所有元素传入到=函数中去,=函数执行的结果就作为apply表达式的结果返回。
这时候,我们可能要问了,为什么不能直接采用(not (= x y more))这样的形式来调用呢?
这儿就涉及我们之前没有提及的一个小问题:[x y & more]这种可变长度参数定义的处理方式。采用[x y & more]
这种定义时,比如,我们传入[1 2 3 4 5],1会被绑定到x,2会被绑定到y,而3、4、5则会被绑定到一个叫more的
集合中去,下面我们验证一下:
user> (defn cus+ ([x] x) ([x y] (+ x y)) ([x y & more] (class more))) #'user/cus+ user> (cus+ 1 2 3 4 5) clojure.lang.ArraySeq
这样子就明白了吧,如果我们直接采用(not (+ x y more))这样的形式,那么传入+函数的就是一个集合,从而
产生参数类型不匹配的异常:
user> (defn cus+ ([x] x) ([x y] (+ x y)) ([x y & more] (+ x y more))) #'user/cus+ user> (cus+ 1 2 3 4 5) clojure.lang.ArraySeq cannot be cast to java.lang.Number [Thrown class java.lang.ClassCastException]
而apply的作用是可以将集合中的所有元素取出来传入对应的函数中去,这样就保障了传入函数的必然是集合中
的元素,而非集合本身。
小于<
<直接用来判断数字的数值大小:
user> (< 1 2 3 4) true user> (< 0x4f 2r11111111 54e5) true user> (< 54M 89) true user> (< \a \b) java.lang.Character cannot be cast to java.lang.Number [Thrown class java.lang.ClassCastException]
如上所见,只要是Number类型的数字都可以进行比较;而不是Number类型的参数就会抛出类型转换异常。让我们
看看源码:
user> (source <) (defn < "Returns non-nil if nums are in monotonically increasing order, otherwise false." {:inline (fn [x y] `(. clojure.lang.Numbers (lt ~x ~y))) :inline-arities #{2} :added "1.0"} ([x] true) ([x y] (. clojure.lang.Numbers (lt x y))) ([x y & more] (if (< x y) (if (next more) (recur y (first more) (next more)) (< y (first more))) false)))
结构跟=函数基本上一模一样,最大的不同就在于二元操作时调用的是clojure.lang.Numbers的lt方法,进行数值
大小的比较。
大于>
>也是直接用来判断数字的数值大小,同样支持多个参数:
user> (> 5 4 3 -1) true user> (> 0xf9 8r6 2r111 5e-2) false user> (> 54M 54) false
可以预见,源码跟<基本一致:
user> (source >) (defn > "Returns non-nil if nums are in monotonically decreasing order, otherwise false." {:inline (fn [x y] `(. clojure.lang.Numbers (gt ~x ~y))) :inline-arities #{2} :added "1.0"} ([x] true) ([x y] (. clojure.lang.Numbers (gt x y))) ([x y & more] (if (> x y) (if (next more) (recur y (first more) (next more)) (> y (first more))) false)))
果然如此,除了调用的是clojure.lang.Numbers的gt方法。
小于等于<=
<=同样也是进行数字的数值判断:
user> (<= 1 1 2 4 5.0 5) true user> (<= 0x3 8r6 2r111 13/2 5e2) false user> (<= 3M 3) true
让我们看看源码:
user> (source <=) (defn <= "Returns non-nil if nums are in monotonically non-decreasing order, otherwise false." {:inline (fn [x y] `(. clojure.lang.Numbers (lte ~x ~y))) :inline-arities #{2} :added "1.0"} ([x] true) ([x y] (. clojure.lang.Numbers (lte x y))) ([x y & more] (if (<= x y) (if (next more) (recur y (first more) (next more)) (<= y (first more))) false)))
同样的结构,除了调用的是clojure.lang.Numbers的lte方法。
大于等于>=
>=也是进行数字的数值判断:
user> (>= 30.33 30 18/5 5e-2) true user> (>= 0xff 8r13 2r1111) false user> (>= 5.43M 5.43) true
可以预见,源码是没什么惊喜了:
user> (source >=) (defn >= "Returns non-nil if nums are in monotonically non-increasing order, otherwise false." {:inline (fn [x y] `(. clojure.lang.Numbers (gte ~x ~y))) :inline-arities #{2} :added "1.0"} ([x] true) ([x y] (. clojure.lang.Numbers (gte x y))) ([x y & more] (if (>= x y) (if (next more) (recur y (first more) (next more)) (>= y (first more))) false)))
发表评论
-
Clojure细节之Reader
2012-05-10 15:19 0前言 Clojure中提供了多种reader语法糖来 ... -
Clojure细节之form和special form的区别
2012-05-07 14:26 2212前言 在lisp程序员看来,form和special ... -
Clojure入门-前言
2012-04-10 09:04 0前言 0.1 关于Clojure 在正式接触Clo ... -
使用c通过jni调用java
2012-04-02 12:01 9346编译环境: fedora16 gcc (GCC) ... -
clojure调用java方法时参数问题
2012-02-24 10:05 1950众所周知,clojure基于jvm,可以在不做引入的情 ... -
换零钱的clojure实现
2012-01-06 19:27 1788题目:有半美元、四分 ... -
clojure API学习(4) 程序流控制
2011-12-20 16:38 0本文基于jdk1.6和clojure1.2 if ... -
clojure API学习(3) 字符和字符串操作
2011-12-16 00:08 4601注:本文基于jdk1.6,clojur ... -
clojure的冒泡排序实现
2011-12-08 17:11 2149冒泡排序的基本概念是:依次比较相邻的两个数,将小数放在 ... -
Clojure-JVM上的函数式编程语言(17)数据库 作者: R. Mark Volkmann
2011-11-26 09:20 1794原帖地址:http://java.ociweb.com/mar ... -
clojure API学习(1) 数学运算
2011-11-24 22:32 2997附注:本文基于jdk1.6,clo ... -
Clojure-JVM上的函数式编程语言(16)Web应用 作者: R. Mark Volkmann
2011-11-19 11:37 1957原帖地址:http://java.ociweb.com/mar ... -
Clojure-JVM上的函数式编程语言(15) 桌面应用 作者: R. Mark Volkmann
2011-11-19 11:04 1510原帖地址:http://java.ociweb.com/mar ... -
Clojure-JVM上的函数式编程语言(14) 编辑器和开发环境 作者: R. Mark Volkmann
2011-11-19 10:31 1674原帖地址:http://java.ociweb.com/mar ... -
Clojure-JVM上的函数式编程语言(13)自动化测试 作者: R. Mark Volkmann
2011-11-17 21:25 1384原帖地址:http://java.ociweb.com/ma ... -
如何将Clojure作为java工程中的脚本
2011-11-17 09:57 0注:本文基于jdk1.6和Clojure1.2 -
Clojure-JVM上的函数式编程语言(12)编译 作者: R. Mark Volkmann
2011-11-17 11:52 2640原帖地址:http://java.ociweb.com/ma ... -
Clojure与java设计模式(3) 策略模式
2011-11-16 15:45 1813注:本文基于jdk1.6和Clojure1.2 策略模 ... -
在eclipse上面搭建Clojure开发运行环境
2011-11-15 13:30 12460首先,需要下 ... -
Clojure和JAVA设计模式(2) 工厂模式之工厂方法
2011-11-15 15:05 1246注:本文基于jdk1.6和Clojure1.2 工厂方 ...
相关推荐
关于这是 Clojure 官方 API 文档的中文翻译版本。在线阅读地址: 。翻译进度模块进度译者clojure.core进行中 , ,clojure.data无 clojure.inspector无 clojure.java.browse已完成clojure.java.io已完成clojure.java...
Clojure Spark API SparkPlug是的Clojure API。 安装 库版本在Clojars上发布。 要将最新版本与Leiningen一起使用,请在您的项目中添加以下依赖项: 这将引入omnibus程序包,而该程序包又取决于相同版本的每个子...
Clojure学习教程.pdf
clojure1.6.0的API文档,英文版
clj-osf clj-osf是一种简单的 Clojure 域特定语言 (DSL),用于查询...文档用法如何使用 API 使用这个 API 真的很简单。 开发人员必须: 在他们的项目中使用 clj-osf 包声明他们想要使用的命名空间通过调用 defosf 和
[2013] Functional Programming Patterns in Scala and Clojure - Write Lean Programs for the JVM.(Michael Bevilacqua-Linn).[1937785475].pdf+epub.rar [2014] Clojure Cookbook - Recipes for Functional ...
【2】clojure_programming.pdf 【3】Practical Clojure.pdf 【4】Programming Clojure with Emacs.pdf 【5】Programming Concurrency on the JVM(Java虚拟机并发编程)(英文版).pdf 【6】programming_clojure_2nd_...
Clojure学习文档,Clojure-Web开发学习,覆盖了Clojure由浅入深的基本学习
Programming Clojure 2nd pdf (第2版),最新2012年出版的,是学习clojure的必备资料。有clojure之父写序。
NULL 博文链接:https://clojure.iteye.com/blog/1741375
用于Kubernetes操作的Clojure工具
clojure-twitter, 面向 Twitter API的Clojure客户端 面向Clojure的 Twitter 客户端 API从Clojure访问 Twitter API 。建筑lein depslein jar示例(require 'twitter ['oauth.
The Joy of Clojure, Second Edition is a deep look at the Clojure language. Fully updated for Clojure 1.6, this new edition goes beyond just syntax to show you the "why" of Clojure and how to write ...
这是Programming Clojure 电子版的 纸质版本在美国亚马逊要到2009年3月才能上架 Paperback: 200 pages Publisher: Pragmatic Bookshelf (March 15, 2009) Language: English ISBN-10: 1934356336 ISBN-13: 978-...
clojure clojure clojureclojure clojure
CHAPTER 2 Rapid Feedback Cycles with Clojure CHAPTER 3 Web Services CHAPTER 4 Testing CHAPTER 5 Reactive Web Pages in ClojureScript CHAPTER 6 The Datomic Database CHAPTER 7 Performance
主要特性:从 Java 中保护你的 Clojure 程序,进行安全的互操作,正确的使用外部 Java 库。Typed Clojure 支持关键字映射的使用,类型检测器中包含有用的映射操作,包括关键字查找,添加或者移除关键字,合并映射...
Practical Clojure Clojure语言书籍
【2】Clojure – Functional Programming for the JVM中文版.pdf 【3】Clojure Cookbook.pdf 【4】Clojure Data Analysis Cookbook.pdf 【5】clojure Hand book(中文).pdf 【6】Clojure in Action.pdf 【7】clojure ...
clojure-tensorflow, Java api的Java上的一个极轻层 和 TensorFlowJava互操作上的包装器层,用于处理 TensorFlow 。 正在启动神经网络示例(ns example.core (:require [clojure-tensorflow.ops :a