Clojure 学习笔记
Clojure哲学
1.又一种Lisp?
优美、灵活、代码即数据。
实现一门程序设计语言,代码同数据一般对待,这需要语言本身具有非常强的可塑性。当语言就是以这种本质的数据结构表现时,语言本身就可以操作自己的结构和行为了。
2.函数式编程?
函数式编程关心和处理的是函数的应用和组合。再进一步,一门被认为是函数式的语言,它的概念一定是一等的。在这门语言里,函数可以存储、可以传递,还可以返回,同语言里的其他数据一样。
3.Clojure不是面向对象的
Clojure是函数式而非面向对象。
定义术语:最重要的术语——时间。面向对象设计里,状态和标识没有清晰区分,而这两个概念合并一个通常可变状态的东西(可变性摧毁了时间、状态和标识这些概念,变成了只有一个)。经典的面向对象模型对对象属性的修改毫无限制,完全不保留历史状态。Clojure的实现尝试在对象状态和标识之间画出一条清晰界限。
这里放个图
不变性是Clojure的基石,Clojure实现的绝大部分都是为了高效地支持不变性。
命令式编程是如今占主导地位的编程范式。命令式程序设计语言用一系列语句修改程序状态。
OOP里的大多数东西,Clojure也有,比如多态(多重方法和协议实现的)和表达式问题(限制?)、子类型化(Clojure可以创建一种特殊的层次结构,提供了子类型化的方式)和面向接口编程(Clojure通过其协议还提供了类似Java接口的能力)、封装(Clojure不以类来组织,如何抽象?),还有就是并非万物皆对象。
Clojure不以类来组织,如何抽象?
拥有闭包的语言自动就支持某种形式的封装,把函数根据其支持的数据进行分组。(没懂)
数据类型
标量👇
- 整数
- 浮点
- 有理数(采用经典的以整数做分子、分母的表示方式)
- 符号(对符号求值,得到当前上下文中符号所指的值)
- 关键字(对关键字求值,会返回他本身,:开头)
- 字符串(+双引号)
- 字符(反斜线\开头)
- 布尔值
- 正则表达式
集合👇
- list(带括号())
- vector(方括号[])
- map(存不重复的键值,花括号{})
- set(不重复的项,#{})
函数👇
- 调用函数(前缀记法)
- 定义函数
- 用def和defn简化函数定义(defn是def的语法糖)
- 以#()定义原位(in-place)函数
var(Clojure中最接近变量的东西)👇
- 使用def声明绑定(def声明不可变绑定,绑定可以是任意类型)
局部量、循环和block👇
- 聚集功能的block
- 创建局部值绑定
- 循环的构造
block(块) 通常指的是 一个代码块,它是一组表达式(expressions)的组合,可以按顺序执行并返回最后一个表达式的结果。
执行多个表达式(按顺序)。
返回最后一个表达式的结果(类似其他语言的
return
)。限制变量的作用域(如
let
块)。
局部量在 Clojure 中由
let
、函数参数、loop
等结构引入。不可变,但可通过嵌套绑定或
atom
模拟变化。作用域严格受限,避免污染全局环境。
优先使用不可变局部量,符合函数式编程风格。
在Lisp里,构建循环的经典方式是递归调用,Clojure也是如此。
在 Clojure 中,循环(Loop) 的实现方式与命令式语言(如 Java/Python)不同,主要采用 递归(Recursion) 和 高阶函数(如
map
、reduce
)来实现迭代操作。由于 Clojure 强调 不可变性(Immutability),传统for/while
循环并不常见。
优先使用高阶函数(如
map
、reduce
)代替显式循环。需要索引或复杂状态时用
loop
+recur
。避免可变状态,如
while
或原子(atom
)。
什么是quote👇
在 Clojure(和其他 Lisp 方言)中,quote
是一种特殊形式(special form),它的作用是 阻止代码被求值(evaluation),直接返回代码本身(即“数据”而非“执行结果”)。
-
quote
是 Clojure 中阻止求值的机制,返回代码的字面形式。 -
简写:
'form
等价于(quote form)
。 -
用途:定义数据、宏编程、符号处理。
-
哲学:体现 Lisp “代码即数据” 的核心思想。
在宏中,参数默认被
quote
,避免提前求值
quote
和eval
是逆操作:
(quote form)
→ 返回form
本身(不求值)。
(eval form)
→ 对form
求值。
与java互操作👇
- 访问静态成员类
- 创建java实例
- 用.运算符访问java实例对象
- 设置java实例属性(像set)
- 宏(把一些方法串联起来,基于前一个方法调用的返回类型调用后一个)
- doto宏(java常常new实例然后赋值;如果采用doto宏,可以使之成为流水线)
- 定义类
异常👇
- 类似java的throw和catch
PS:什么form?
在 Clojure(和其他 Lisp 语言)中,form(形式) 是一个核心概念,指的是 任何可以被求值(evaluated)的代码单元。
form = 可求值的代码单元(值、符号、列表、数据结构等)。
Clojure 程序由嵌套的 form 组成,体现“代码即数据”。
特殊 form(如
if
、def
) 有独特的求值规则。
命名空间👇
Clojure的命名空间提供一种“将相关函数、宏以及值放在一起”的方式。
- 用ns创建命名空间
- 用:require加载其他命名空间
- 用:use加载和创建映射
- 用:refer创建映射
- 用:import加载java类