Clojure快餐教程(1) - 运行在JVM上的Lisp方言

Clojure快餐教程(1) - 运行在JVM上的Lisp方言

Java作为目前为止被使用最广泛的使用虚拟机的编程语言,带动了JVM上语言族的繁荣。
有根红苗正的为JVM设计的动态语言Groovy,目前最主要被用于Gradle编译环境中;也有Jython, JRuby等动态语言在JVM上的实现,也有scala这样强大的混合语言。
在这之中,clojure是比较特殊的一种,它是Lisp语言在JVM上的一种方言。

使用clojure调用java

首先我们先看一下如何用clojure来调用java的方法。
有了这个利器之后,我们就获得了整个java世界的类库的强大支持。

首先我们看个例子,做个最简单的两个大整数的乘法。用Java写是这样风格的:

import java.math.BigInteger;

public class Test {
    public static void test(){
        BigInteger bi1 = new BigInteger("1234567890");
        BigInteger bi2 = new BigInteger("9876543210");
        System.out.println(bi1.multiply(bi2));
    }
}

用Clojure写起来,一开始可能会有点不适应,会是这样的:

(ns .test2)
(import java.math.BigInteger)

(println (.multiply (new BigInteger "1234567890") (new BigInteger "9876543210")))

这里可能会给代码补全带来一点困难,因为在写.multiply时,还不知道它是应用在哪个对象或者类上。但是Clojure就是这种风格了,函数名、运算符先行。

Clojure对于Lisp的改进

Clojure作为运行在JVM上的Lisp方言,第一个优势就是可以无缝调用Java API。另外,针对Lisp括号多的问题,Clojure除了S表达式中常用的()之外,增加了[]{}两种括号。

()表示列表,[]表示向量,{}用于表示哈希表。
另外,#{}用来表示集合。

user=> (class [])
clojure.lang.PersistentVector
user=> (class ())
clojure.lang.PersistentList$EmptyList
user=> (class {})
clojure.lang.PersistentArrayMap
user=> (class #{})
clojure.lang.PersistentHashSet

在Clojure中生存

查看帮助 - clojure.repl/doc

doc宏用于查看常量、特殊表、函数或者宏的文档。在以后的编程中我们会经常使用它。

例:

user=> (doc doc)
-------------------------
clojure.repl/doc
([name])
Macro
  Prints documentation for a var or special form given its name

列表

在Lisp中,列表数据和代码的表示形式一样,都是S表达式。S表达式可以通俗理解为一个括号括起来的,以第一个符号进行求值的表达式。
所以,如果要避免一个列表被求值,我们有两种办法:

  1. 用list函数来生成列表
  2. 用quota特殊表来避免被求值

例:

user=> (list 1 2 3)
(1 2 3)
user=> (doc list)
-------------------------
clojure.core/list
([& items])
  Creates a new list containing the items.
nil
user=> (quote (2 3 4))
(2 3 4)
user=> (doc quote)
-------------------------
quote
  (quote form)
Special Form
  Yields the unevaluated form.

  Please see http://clojure.org/special_forms#quote
nil
user=> '(3 4 5)
(3 4 5)

"'"符号是quote的简写形式。

列表操作

lisp中最常用的car和cdr在clojure中不被支持,�当然更不用想caddr之类的了。

如果要取表头,需要使用first函数,例:

user=> (first (list 2 3 4))
2

相对地,取除了表头之外的部分,使用rest函数,例:

user=> (rest (list 2 3 4))
(3 4)

如果取最后一个元素,可以�使用last函数获取最后一个元素,例:

user=> (last '(5 6 7))
7

一般地,我们如果想取第n个下标的元素的话,可以使用nth函数:

user=> (nth (list 8 9 10) 2)
10

虽然没有car和cdr,但是将fist和rest连接在一起的cons函数还是有的:

user=> (cons 1 '(2 3 4))
(1 2 3 4)

向量

向量有点类似于数组,对于随机访问元素进行优化。�clojure使用中括号来表示向量。
由于不是用的S表达式,所以也就不用quote了。
first, last, nth和rest函数对于向量仍然适用。

user=> (first [1 2 3 4])
1
user=> (nth [4 5 6 7] 3)
7
user=> (rest [3 4 5 6])
(4 5 6)

但是请注意rest返回的并不是一个向量,而且一个序列类型。
我们可以用class函数来看一下具体的类型:

user=> (class (rest '(1 2 3)))
clojure.lang.PersistentList
user=> (class (rest [1 2 3]))
clojure.lang.PersistentVector$ChunkedSeq

哈希表

用完了小括号和中括号,下面是大括号出场的时候了。没错,大括号用来表示哈希表。例:

{:name "hello", :age 18}

访问使用键的名字为函数名来获取值,例:

user=> (:name {:name "Hello", :age 18})
"Hello"

集合

小中大括号都用完了肿么办,只好在大括号之前加个"#"来表示。例:

user=> #{ 1 2 3}
#{1 3 2}

集合中的元素不能重复。如果要构建一个set,可以使用sorted-set函数。

user=> (sorted-set 1 2 2 3)
#{1 2 3}

变量绑定

使用def特�殊表可以将值绑定到一个全局变量上。
前面学习的数据结构,现在都可以用来绑定到变量上了。
def可以多次绑定,以最新绑定的值为准。例:

user=> (def a '(1 2 3))
#'user/a

定义函数

作为Lisp的一种方言,函数是一定在生存阶段要学懂的必备技能。

我们使用fn特殊表来定义函数,如果作为函数对象,或者叫做lambda表达式,可以不定义名字。

比如,我们定义一个求平方的匿名函数:

user=> (fn [i] (* i i))
#object[user$eval17$fn__18 0x7f284218 "user$eval17$fn__18@7f284218"]

函数没有什么特殊的,也可以用def绑定到一个变量上,这就是我们通常定义函数的写法:

user=> (def sqr (fn [i] (* i i)))
#'user/sqr
user=> (sqr 4)
16

我们也可以使用defn宏来定义函数:

user=> (defn sqr3 [i] (* i i i))
#'user/sqr3
user=> (sqr3 4)
64

�通过defn宏,还可以为函数提供说明文档,然后文档就可以通过doc函数来看了。例:

user=> (defn succ "return next x" [x] (+ x 1))
#'user/succ
user=> (doc succ)
-------------------------
user/succ
([x])
  return next x
nil

小结

  • Clojure是一门运行在JVM上的Lisp方言。与Lisp还是有一些不同,比如使用[],{},#{}来表示向量、哈希表和集合。比如不支持car, cdr, �setq等。
  • Clojure支持通过import宏来引用java包
  • Clojure通过new特殊表可以创建java对象
  • clojure.core/doc函数用来查看帮助文档
  • �def特殊表用于绑定变量
  • fn特殊表用于定义函数,主要用于定义匿名函数
  • defn宏可以定义函数的说明文档
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容