Clojure 入门
我将尝试教一些人(主要是Python开发者,在OS X操作系统运行)如何使用Clojure, 因为我觉得目前已经存在的一些教人如何从零开始学习Clojure的文档不尽如人意。 当我自己在几个月前亲身经历这一切,这是一个奇怪的时期, 好几个星期我一直处于迷茫中, 我基本上找不到一个关于Clojure生态系统的概念路线图,也不知道如何组织一个。
我这篇文章的目标是创建该资源(我本该六个月前就创建它)。我将假设您正使用OS X操作系统并且有些许编程经验
关于 Clojure 的书籍
你首先应该购买并开始阅读 Clojure Programming. 还有另外一本叫“Programming Clojure” (书名有点容易混淆) ,我不能保证说它更好或者更差, 但我喜欢 “Clojure Programming” 并且一直使用它,所以我推荐它。 写这本书的人都是那些你搜索Clojure社区时常常见到的大牛们的名字。在Clojure社区, 所有主要的人物似乎都毫无人性地多产。
让我们开始吧
现在,让我们开始配置你的环境。 获取Homebrew -“OS X缺省的包管理器” – 准备好后, 运行下面的命令:
1
|
brew install clojure
|
这个命令将安装一个Clojure 副本,你可以通过‘clj’ 命令进行访问。 继续并运行它,你会看到REPL启动, 随便发挥吧。 你会发现自己并不是常常用到这个副本, 但是有它总是好的,特别是当你想直接运行一个Clojure 文件可以通过命令`clj a_file.clj`进行。
你不会经常用到’clj’ 是因为REPL默认的原始的Clojure环境非常的垃圾。它不支持使用向上箭头访问之前计算的表达式; 它不支持使用’C-a’ 和’C-e’到达每一行的开始/末尾;这真的非常气人, 你会讨厌它的, 因此别使用它。
你下一个步骤是安装Leiningen, 从现在开始你几乎会从不间断地用到它。通常, 你需要安装 Leiningen 2, 虽然它目前还不是Leiningen的公开的发行版本,但相信我它就是你要安装的版本。你可以通过运行下面的命令得到它:
1
|
brew install leiningen - - devel
|
这个 –devel 标记, 告诉Homebrew 我们需要的是 Leiningen 2 而不是 Leiningen 1.x. 我花了不少时间才搞懂它。
那么Leiningen究竟是什么鬼东西?
Leiningen是你的主要工具, 它用于:
- 启动一个 REPL
- 下载+安装类库
- 运行你的程序
- 启动一个服务器, 运行你所写的webapps
接着运行 `lein repl`. 它会启动一个真正有用的 REPL, 任何时候,当你需要一个REPL,用这个命令就行。 使用向上方向键你会得到之前用过的计算表达式, 而快捷键 C-a 和 C-e 也能生效(到达行首/行尾), 一切都像你所期望的那样。另外,如果你在顶级目录运行一个Clojure 项目,它会根据实际情况处理连接类路径和诸如此类的东西,这样你就可以导入和玩玩你项目的代码和库了。 稍后我们再讨论这个。现在,让我们通过下面的命令创建一个骨架项目玩玩:
1
|
lein new foo
|
命令完成后, cd 到 foo 目录,你会看到它已经有了一些文件和目录:
1
2
3
4
5
6
7
|
[jrheard@jrheard - air:~ / dev / foo] $ ll
total 16
- rw - r - - r - - 1 jrheard staff 193B Jan 5 15 : 17 README.md
drwxr - xr - x 3 jrheard staff 102B Jan 5 15 : 17 doc
- rw - r - - r - - 1 jrheard staff 263B Jan 5 15 : 17 project.clj
drwxr - xr - x 3 jrheard staff 102B Jan 5 15 : 17 src
drwxr - xr - x 3 jrheard staff 102B Jan 5 15 : 17 test
|
当你写一个Clojure 库/程序/或者任何东西,你的源代码都保存在“src”目录,你的测试代码则保存在“test”目录。非常简单。 让我们来看看 src 目录:
1
|
[jrheard@jrheard - air:~ / dev / foo] $ cat src / foo / core.clj
|
1
|
(ns foo.core) (defn foo "I don't do a whole lot." [x] (println x "Hello, World!" ))
|
看起来 Leiningen 已经创建了一个叫 “src/foo/core.clj” 的文件。这是一个Clojure程序, 它定义了一个“foo.core”的命名空间, 然后声明该命名空间包含一个名为“foo”的函数。 我们来看看它。用`lein repl`启动一个REPL 并浏览一下。 还记得我前面提到过Leiningen会负责处理你的类路径和相关的goop,这样你就可以从REPL访问你的项目代码了? 看看这个:
1
2
3
4
|
user = > (use 'foo.core) nil
user = > foo #<core$foo foo.core$foo@6ad591a6>
user = > (foo "jrheard" ) jrheard Hello, World!
nil
|
真棒 – 我们已经能够导入我们的代码并运行它。 `use` 提供了类似于Python里面的`from foo.core import *` 相同 的功能,因此不鼓励在源代码中再使用它( from foo.core import *), 出于相同的原因, import *也不再鼓励使用。不过像 import * ( 这样的功能), 在你查找(浏览)REPL 的时候是相当有用的。
嘿,非常酷 – 我们已经创建了一个项目, 里面还生成一些代码, 我们已经知道如何启动一个能运行的REPL 还可以在里面浏览那些代码。 第一阶段已经完成啦, 让我们来看看第二个阶段:
下装并安装类库
你可能习惯在命令行运行一些命令来获取类库。例如 `pip install this_great_library_i_found`, 它会下载你指定的类库, 并安装到全局的或者你当前的虚拟环境中(virtualenv)。 但是在 Clojure 里, 有一点点不一样。
首先,你必须找到一个看起来还不错的类库。 Clojure Toolbox 是一个奇妙的工具,这是我发现的最好的资源。 我们选择一个库玩玩: 创建HTTP请求很有意思 – 让我们先到 “HTTP Clients” 的章节, 看看我们都有哪些选择。 看起来我们得在 clj-http 和 http.async.client 之间挑一个 -但是选哪一个呢?
目前,在多个存在竞争关系的类库之间做选择时,我最喜欢的方式是:把它们从github仓库里拉下来,然后比较加星数和fork数之和,如果最近两个月有提交代码可以加分,用这个数代表社区的健壮性、影响力或适应能力,可能不是特别科学,不过我用着挺好的。在写这篇文章的时候,clj-http有242个星号,http.async.client只有127个,所以我选择clj-http。
所以… 怎么搞到它?
让我们打开 clj-http’s github repo。README中关于安装那一段有如下代码:
1
|
[clj - http "0.6.3" ]
|
这就是我们需要的信息 – 这是一个 Clojure vector,它包含两个条目,第一个条目是类库的名字, 第二个条目标识最新的稳定版本。我们打算把它添加到我们的(你之前在查看’foo’ 目录的内容看到的那一个) project.clj. 打开 project.clj, 看起来就像这样:
1
2
3
4
5
6
|
(defproject foo "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html" }
:dependencies [[org.clojure / clojure "1.4.0" ]])
|
注意:dependencies 那段 – 这是一个包含一个条目的Clojure vector, 该条目本身也是一个包含两个条目的的 Clojure vector. 这个 vector 告诉 Leiningen 我们的项目要运行在版本是1.4.0的Clojure 上.够公平的了,现在让我们添加我们之前看到的那个clj-http vector。 现在 project.clj 看起来应该像这样:
1
2
3
4
5
6
7
|
(defproject foo "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html" }
:dependencies [[org.clojure / clojure "1.4.0" ]
[clj - http "0.6.3" ]])
|
就是这样!现在我们已经指定了我们需要的clj-http类库和版本号。让我们试一下 -使用`lein repl`命令启动一个REPL,来测试我们精选的新类库。要注意的是,在REPL启动的时候Leiningen会首先下载clj-http,这是因为基本上在我们的所有操作之前,它会先在后台执行`lein deps`命令扫描 project.clj文件,并且确保已经获取到了所有我们需要的依赖类库。
好的,回到我们的REPL会话,这里有一个从clj-http的github上返回的README,它告诉我们需要在REPL上运行
1
|
(require ‘[clj - http.client :as client])
|
好吧我们运行一下,-这跟Python中’from clj.http import client’是一样的(与`from clj.http.client import *`截然相反,这也是’use’函数的工作)
1
2
|
user = > (require '[clj - http.client :as client]) nil
user = > (client / get "http://www.yelp.com" ) ;; a big huge blob of data pops out!
|
哇,好了,看到它能运行了!那些排列读起来很糟糕——你会发现以”}”结束的超大块的数据,那大概是Clojure map类型的小许数据。接下来试试下面的代码:
1
2
3
4
5
6
7
8
9
|
user = > ( def resp (client / get "http://www.yelp.com" )) #'user/resp
user = > ( type resp) clojure.lang.PersistentArrayMap
user = > (keys resp) (:cookies :trace - redirects :request - time :status :headers :body)
user = > (:status resp) 200
user = > (:headers resp) { "server" "Apache" , "content-encoding" "gzip" , "x-proxied" "lb2" ,
"content-type" "text/html; charset=UTF-8" , "date" "Sun, 06 Jan 2013 00:02:58 GMT" ,
"cache-control" "private" , "vary" "Accept-Encoding,User-Agent" ,
"transfer-encoding" "chunked" , "x-node" "wsgi, web40, www_all" ,
"x-mode" "ro" , "connection" "close" }
|
运行之后,我们发现了一个HTTP客户端库,下载它,并且指出怎样在REPL中交互使用。
把它们都找出会花掉我一些时间——在用头撞了一天墙之后,我终于不得不来到#clojure IRC 频道请示帮助。现在你不用那样做了!想进一步阅读的,请看 the official Leiningen tutorial。
把它们全部放一起
让我们通过弄清如何实际运行一个Clojure程序来完成。我们尝试一个典型的`lein run`:
1
2
|
[jrheard@jrheard - air:~ / dev / foo] $ lein run
No :main namespace specified in project.clj.
|
好的,这没成功运行。返回之前提到过的Leiningen手册然后搜索下:main,我们看到你可以第一个一个:main关键字在你的project.clj定义里来指定`lein run`会执行的命名空间,也就是说这个命名空间必需包含一个`-main`的函数来为你的程序提供入口点。让我们把这行代码加入到我们的project.clj定义里:
1
|
:main foo.core
|
最后我们修改src/foo/core.clj,然后它的代码如下:
1
2
3
4
5
6
7
8
9
|
(ns foo.core
(:require [clj - http.client :as client]))
(defn - main
"Prints the first 50 characters of the HTML source of yelp.com."
[& args]
(println ( apply str
(take 50
(:body (client / get "http://www.yelp.com" ))))))
|
到这里,我们继续尝试`lein run`:
1
2
3
4
|
[jrheard@jrheard - air:~ / dev / foo] $ lein run
Compiling foo.core
<!DOCTYPE HTML>
<! - - [ if lt IE 7 ]> <html xmlns:fb
|
它成功了!
目前来说-你现在有了一个可运行的REPL来玩耍,安装和使用库的能力,让你的程序访问这些库以及运行的知识,还有一本真正能给你一切你所需知道的关于Clojure语言的好书。
我为何必须写这篇文章
Clojure还是一门非常年轻的语言。跟Python比的话,它的社区也还特别小。尽管我说过它的核心API非常稳定,但很多周边工具都是新的而且还在快速变化。最重要的是你会发现很多最新的文档都没有做好SEO,大部分的Google搜索结果都会转到richhickey.github.com,而它上面的很多东西都过时了。所以你会觉得Clojure很难上手。
希望本文能让你少迷茫几个星期,避免重蹈我的覆辙。我保证成长的痛苦是值得的,Clojure会让你享受到编程的真正乐趣。
各种资源
- 看看 Rich Hickey(clojure 的创始人)的两个演讲 : “Are We There Yet?” 和“Simple Made Easy”. 特别注意的是,过几个月看下第一个演讲三到四次。
- 我花了过去的几个星期看了所有有关clojure的演讲。官方youtube频道不错 official Clojure youtube channel , InfoQ也有很多不错的内容( great content on InfoQ ),我在这最少看了25个演讲。
- The Clojure Toolbox, 寻找现成的库
- Where Did Clojure.Contrib Go - 你要查看一些库的手册,比如“clojure.contrib.monads, 正像你看到的, clojure.contrib 这个库不会存在多久, 这个页面会告诉你 库被合并到哪去了。
- This example project.clj 展示了很多Leiningen提供的钩子(hooks)不同的高级用法,轻松定制,构建你的项目
- 你可以在twitter上 following clojure 社团的核心成员 @cgrand, @cemerick, @marick, @weavejester, @stuartsierra, @seancorfield, @Baranonsky, @richhickey
- 读 “The Joy of Clojure” 如果你已经看完了 “Clojure Programming”.
- 特别注意,Noir已经不维护了,使用Compojure代替吧
Clojure 入门相关推荐
- Clojure入门指南(Getting Started)
Clojure入门指南 http://clojure.org/getting_started 快速开始 要求Java 1.5或者更高版本(JavaSDK). 下载(http://clojure.org ...
- Clojure入门教程: Clojure – Functional Programming for the JVM中文版
http://xumingming.sinaapp.com/302/clojure-functional-programming-for-the-jvm-clojure-tutorial/ api:h ...
- Clojure入门教程
Clojure入门教程: Clojure – Functional Programming for the JVM中文版 发表于 2011 年 12 月 07 日 由 xumingming 作者: x ...
- clojure入门: hello world
Hello World 你需要jdk1.5或者以上的版本. 下载并且解压clojure, 在你解压clojure的目录里面执行: 帮助 1 java -cp clojure.jar clojure.m ...
- Clojure 学习入门(13)- binding
Clojure里面是不支持变量的.Binding跟变量有点像,但是在被赋值之前是不允许改的,包括:全局binding, 线程本地(thread local)binding, 以及函数内的本地bindi ...
- Clojure 学习入门(1) - 学习资料
转自:http://blog.csdn.net/ithomer/article/details/17225813 Clojure(发音类似"closure",['kləʊʒə(r) ...
- Clojure学习1---基础语法
概述 Clojure是一种高级的,动态的函数式编程语言. Clojure是基于LISP编程语言设计的,并且具有使其在Java和.Net运行时环境上运行的编译器. Clojure作为一种编程语言,具有以 ...
- 免费的编程中文书籍索引(2018第三版)
之前我在 github 上整理了来一份:free-programming-books-zh_CN(免费的计算机编程类中文书籍). 截至目前为止,已经在 GitHub 收获了 40000 多的 star ...
- Storm原理与实现
2019独角兽企业重金招聘Python工程师标准>>> Storm原理与实现 转自:http://duanple.blog.163.com/blog/static/709717672 ...
最新文章
- java编写数字金字塔_用JAVA写数字金字塔
- RosBE生成ReactOS的VS2015工程失败2
- android:descendantFocusability
- [转载]配置unp.h头文件环境
- 这年头学爬虫还就得会点 scrapy 框架
- php sql语句过滤,php如何做sql过滤
- 华为诺亚CV方向19篇论文入选ICCV 2019
- dubbo go中的TPS Limit设计与实现 滑动窗口、固定窗口有什么区别?
- java datasource mysql_java – 添加新的Datasource(mysql)wildfly
- 漫画:什么是希尔排序?
- c语言message函数应用,调用input_message的参数太少在主函数中 是神马意思 大神们帮帮我...
- 【bzoj 3131】[Sdoi2013]淘金
- Codeforce 1600Difficulty Graphs 20 questions
- 微型计算机原理与接口技术
- Cesium中的相机—方向余弦阵
- Image data cannot be converted to float
- linux命令里的xz是干嘛的,Ubuntu中的xz命令使用
- 从网易博客转入CSDN
- JAVA范例 - Applet小应用程序
- java简单实现求平方根
热门文章
- 【Java 虚拟机原理】垃圾回收算法( Java VisualVM 工具 | 安装 Visual GC 插件 | 使用 Java VisualVM 分析 GC 内存 )
- 【Android 安装包优化】Android 中使用 7zr 可执行程序 解压缩文件
- 【计算理论】计算理论总结 ( 泵引理 Pumping 证明 ) ★★
- 【计算机网络】网络层 : 网络层设备 ( 路由器 | 输入端口处理 | 输出端口处理 | 物理层、数据链路层、网络层 设备对比 | 路由表 与 路由转发 )
- 【Android 应用开发】Android 网络编程 API笔记 - java.net 包相关 接口 api
- 【BZOJ1294】[SCOI2009]围豆豆(动态规划,状压)
- 构建之法第三章软件工程师的成长
- 小白的.Net Core 2.0 ConsoleApp入门(keng)指南(一)
- 数据结构与算法系列 目录
- update与merge