ivaneye.com

Clojure教程-Record和Protocol

本文翻译自:Learn Clojure using records and protocols

当我对Clojure的括号不再疑惑后,另一个让我质疑为何要学习Clojure的问题是使用REPL很爽,但是我怎么来构建大型项目?".

实际上,由于我的面向对象编程经验,我其实要问的是"我怎么才能将函数封装到类似class的东西里面去?".

在本文中,我将会介绍一种类似于Java的方式来构建大型的Clojure项目.

通过这种方式,希望你在学习Clojure的时候不会有太大的差异感!

在Java中,我们出于各种目的而使用类.例如典型的使用Spring的web应用,你会看到类似下面的结构:

DTO实际上就是个结构体,他没有任何的行为(即方法).为了最小化样板代码,我趋向于使用pulibc final属性去实现DTO.我认为DTO就是个模板(schema),它就像一个REST服务输出的文件.但是我发现很多客户端开发人员可不关注这个,而只关注代码形式.有时你会看到DTO被作为数据库访问的一部分.这些DTO被称为贫血模型.(译者注:猜测作者的意思是,有些开发人员不管类是DTO还是DAO,只要结构相同就随便用!)

Service实际上是包含了方法和注入了辅助Service的单例对象.不同的辅助Service提供了不同的服务.除了实现了接口外,Service只是包含了方法,和占位符很类似.单例模式导致的一个问题就是,新手无法预见到多线程里共享相同的实例出现意外的结果.他们将状态保存到私有属性里,而不需要从一个对象传递到另一个对象.很方便,但是是错误的做法.

Rich object是面向对象语言中的思想.即将数据及和数据相关的操作封装到一个类里面.我可没说getter和setter是相关操作!但是,rich object类在项目中用得较少.取而代之的是使用DTO作为Service的输入和输出.使用DAO来访问数据库,然后返回DTO.我没说这种方法是错误的,我好奇的是,既然对于目前的Java架构是好是坏我们都无法确认,那为什么还要强求使用Clojure去实现类似的东西呢?

Clojure教程-函数

本文翻译自Functions in Clojure

本文包括如下内容:

版权:

This work is licensed under a Creative Commons Attribution 3.0 Unported License (including images & stylesheets). The source is available on Github.

针对Clojure版本

Clojure 1.5

简介

Clojure是函数式编程语言.自然的,函数是Clojure非常重要的一部分.

如何定义函数

函数定义一般使用defn宏:

(defn round
  [d precision]
  (let [factor (Math/pow 10 precision)]
    (/ (Math/floor (* d factor)) factor)))

类型提示有时能避免编译器使用反射,从而能生成更高效的字节码.但是,基本上你没必要使用类型提示.后期优化时再考虑.

函数可以添加注释文档,给API添加文档说明是个好习惯:

(defn round
  "Round down a double to the given precision (number of significant digits)"
  [d precision]
  (let [factor (Math/pow 10 precision)]
    (/ (Math/floor (* d factor)) factor)))

在Clojure中函数参数可以有类型提示,不过是可选的.

(defn round
  [^double d ^long precision]
  (let [factor (Math/pow 10 precision)]
    (/ (Math/floor (* d factor)) factor)))

函数还可以定义前置和后置条件来限制函数的参数和返回值.

(defn round
  "Round down a double to the given precision (number of significant digits)"
  [^double d ^long precision]
  {:pre [(not-nil? d) (not-nil? precision)]}
  (let [factor (Math/pow 10 precision)]
    (/ (Math/floor (* d factor)) factor)))

在上面的例子中,我们使用了前置条件来检查两个参数是否为nil.

not-nil?宏(或函数),没有在该例子中展示,我们假设它已经在其它地方实现了.

Clojure教程-数学计算

本文翻译自Mathematics with Clojure

本文包含了使用Clojure的内建函数,扩展包和部分JDK功能进行数学计算.

版权:

This work is licensed under a Creative Commons Attribution 3.0 Unported License (including images & stylesheets). The source is available on Github.

准备

这里的一些例子使用了math.numeric-towermath.combinatorics库.所以需要 你在代码的命名空间中包含如下代码:

(:require [clojure.math.numeric-tower :as math]
          [clojure.math.combinatorics :as combo])

或者在REPL里载入:

(require '[clojure.math.numeric-tower :as math])
(require '[clojure.math.combinatorics :as combo])

方法

简单计算

(+ 3 4)    ;=> 7
(- 3 4)    ;=> -1
(* 3 4)    ;=> 12
(/ 3 4)    ;=> 3/4  (an exact ratio)
(/ 3.0 4)  ;=> 0.75
(inc 5)    ;=> 6
(dec 5)    ;=> 4

想要计算整数的除法,取余和取模,请看quot,rem,mod 想计算指数的平方根,四舍五入,上下限,绝对值和最大公约数/最小公倍数,请看math.numeric-tower

三角函数

使用Java平台提供的函数:

Math/PI       ;=> 3.14159...
(Math/sin x)
(Math/cos x)
(Math/tan x)

还有很多的函数,你可以查看java.lang.Math

组合数学

对于组合数学相关函数(比如:combinations和permutations),请看math.combinatorics

Clojure教程-文件处理

本文翻译自Working with Files and Directories in Clojure

本文介绍使用Clojure的clojure.java.io命名空间下的函数以及JDK相关方法来操作文件和目录.

版权:

This work is licensed under a Creative Commons Attribution 3.0 Unported License (including images & stylesheets). The source is available on Github.

准备

请注意,在下面的例子中,"io"是clojure.java.io命名空间的简写引用.请确保你的ns宏包含如下代码:

(:require [clojure.java.io :as io])

或者在REPL中加载了:

(require '[clojure.java.io :as io])

方法

将文件读到字符串中

(def a-long-string (slurp "foo.txt"))

注意,你可以给slurp函数传递url.请看slurp文档

一行一行的读取文件

假设你想针对文件的每行内容调用my-func函数,并返回结果序列:

(with-open [rdr (io/reader "foo.txt")]
  (doall (map my-func (line-seq rdr))))

doall函数是必须的,因为map函数返回的是个lazy序列.line-seq返回的每行内容没有是去除了末尾的回车标记的,且空行将返回空字符串.

Clojure教程-字符串处理

本文翻译自Strings

本文内容包括使用Clojure内建的函数和标准库来操作字符串,以及JDK中的相关操作.

版权:

This work is licensed under a Creative Commons Attribution 3.0 Unported License (including images & stylesheets).

源代码在Github上.

概述

    "foo"    java.lang.String
    #"\d"    java.util.regex.Pattern (正则表达式,匹配一个数字)
    \f       java.lang.Character (表示'f')

预备知识

一些例子用到了clojure.string,clojure.edn和clojure.pprint.我们假设你的ns宏里面已经包含了如下内容:

(:require [clojure.string :as str]
          [clojure.edn :as edn]
          [clojure.pprint :as pp])

或者在REPL里面,你需要载入:

(require '[clojure.string :as str])
(require '[clojure.edn :as edn])
(require '[clojure.pprint :as pp])

Clojure教程-基本语法

简介

学习一门语言最好的方法就是去使用它。我们就从一个小例子来学习Clojure语法.

核心语法

首先先来看一下Clojure的核心语法。

Clojure的使用的是Lisp语法,又叫S表达式。核心语法非常的简单。但是对于熟悉c系语法(c,c++,java)的朋友来说,第一次接触会非常的不习惯。

以前面的hello world程序为例。

(println "Hello World")

它以"("开始,后面跟的是函数println,接着空格跟的是参数"HelloWorld",最后")"结尾。

了解了如上规则,你就基本学会了Clojure的大部分语法。

下面比较一下Clojure,Java,Python,Ruby的一些语法.

Clojure 表达式 对应的 Java 语法 对应的 Python 语法 对应的 Ruby 语法
(not k) !k not k not k or !k
(inc a) a++、++a、a += 1、a + 1^a a += 1、a + 1 a += 1
(/ (+ x y) 2) (x + y) / 2 (x + y) / 2 (x + y) / 2
(instance? java. util.List al) al instanceof java.util.List isinstance(al,list) al.is_a? Array
(if (not a) (inc b) (dec b)) !a ? b + 1 : b - 1 b + 1 if not a else b-1 !a ? b + 1 : b - 1
(Math/pow 2 10)^c Math.pow(2, 10) pow(2, 10) 2 ** 10
(.someMethod someObj "foo" (.otherMethod otherObj 0)) someObj.someMethod("foo" , otherObj.otherMethod(0)) someObj.someMethod("foo" , otherObj.otherMethod(0)) someObj.someMethod("foo" , otherObj.otherMethod(0))

可以看出Clojure的语法有高度的一致性,即使你不熟悉S表达式,但是依据上面的原则,可以看懂它想表达的是一个什么意思。

而对于其他三门语言,如果你没有一个个的学习相应的语法,你还是比较难理解它的意思的。

代码功能

了解了核心语法,我们就可以来编写代码了。我们要编写的代码功能很简单,进行简繁翻译,其中过滤不需要翻译以及需要特殊翻译的文字。我们将分几步来完成:

Clojure教程-环境搭建与Hello World

环境搭建

Clojure是JVM上的一种语言,其语法是Lisp格式,所以称为是JVM上的Lisp方言。

Clojure依赖于JDK。请确保你的机器上安装了JDK6+。Clojure的安装非常的简单。 可以分为两种方式:

通过Leiningen是比较普遍也很方便的方式。我们先通过Leiningen来安装。

通过Leiningen安装

Leiningen和Maven比较类似,是Clojure语言的管理工具。其实它就是基于Maven 构建的。我们先来安装Leiningen

leiningen会自动下载需要的依赖。运行完成后,Clojure开发环境即安装完成。

手动安装

leiningen需要以项目为单位才能运行。比如你想运行一个hello.clj程序,如果 你通过leiningen来运行,则hello.clj需要在lein项目内,且设置为core,才能 运行,比较麻烦(这个问题在Maven中同样存在)。

而通过手动安装可以解决这个问题。

java -jar /home/ivan/soft/clojure-1.5.1/clojure-1.5.1.jar $1
 #clojure.jar请输入你本机的路径

这样就可以执行单个的Clojure文件了