0
Clojure的魅力<br />伯岩<br />boyan@taobao.com<br />2010-08-10<br />
Agenda<br />Clojure基础<br />Clojure语法和数据结构<br />Sequences<br />与java交互<br />并发<br />实现<br />缺陷<br />总结<br />2<br />
What is clojure?<br />A dynamic programming language for JVM<br />Clojure is a Lisp<br />Clojure is functional<br />Suppor...
Clojure is a Lisp<br />Clojure是Lisp的一种方言,就像scheme、common lisp也是Lisp的方言一样。<br />Clojure同样也是Homoiconicity(同像性)<br />Homoicon...
Hello World<br />REPL——交互式编程环境<br />user=> (println "hello world")<br />        hello world<br />        nil<br />5<br />
Code vs. Data<br />从代码角度<br />                              (println "hello world")<br />函数           参数<br />   从数据角度<br ...
Clojure的数据类型<br />Integer   –123456789<br />Double 1.234<br />BigDecimal 1.234m<br />Ratios(分数)22/7<br />Strings  “hello”<...
数据结构<br />List单向链表<br />(1 2 3 4 5) (list a  c)<br />Vector类似数组,索引访问<br />[1 2 3 4 5] [foo bar]<br />Map   key/value<br /...
语法<br />前缀运算符<br />(+ 1 2 3)  (println (str “hello “ “world”))<br />(op …), op可以为<br />少数几个special form<br />Macro<br />返回...
传统的求值模型<br />2010—8-10<br />淘宝内部分享-伯岩<br />10<br />
Clojure的求值模型<br />2010-08-10<br />淘宝内部分享-伯岩<br />11<br />
Symbols<br />可以理解成变量,绑定特定的值<br />user=> a<br />   java.lang.Exception: Unable to resolve symbol: a in this context (NO_SOU...
let和binding<br />let是用词法作用域的不可变值“遮蔽”了外部的symbol绑定值。<br />Binding则是创建thread-local级别的symbol绑定值。<br />例子:<br />(def foo 1)<br ...
Special forms<br />(def name init-value?)  <br />定义全局变量<br />(if test then-expr else-expr)<br />条件语句<br />(quote form)<br ...
Macro——宏<br />Macro是Clojure元编程的主要方式<br />什么是Macro?<br />模板语言<br />C语言的预处理器<br />unless:<br />(defmacro unless [test expr]<...
Macro<br />`<br />Syntax quote       标记为模板<br />~<br />Unquote            替代value<br />~@<br />Splicing unquote   拼接list的内...
函数<br />Clojure是FP——函数式编程语言<br />函数是First-Class Values<br />作为参数<br />作为返回值<br />保存为变量<br />(def square (fn [x] (* x x)))<...
高阶函数<br />18<br />
高阶函数<br />以信息流的方式去组织代码,高阶函数带来了约定接口的抽象<br />19<br />range:<br />integers<br />map:<br />fib<br />filter:<br />even?<br />
语法小结<br />20<br />
Sequences<br />传统Lisp中list的抽象<br />(cons item seq)<br />将item插入seq的首部创建新的seq<br />(seq coll)<br />如果集合为空,返回nil,否则返回集合的seq<...
Sequence(1)<br />22<br />
Sequence(2)<br />(iterate inc 0)<br />自然数集合<br />(use ‘[clojure.contrib.lazy-seqs :only(primes)])<br />   (def ordinals-an...
Sequence(3)<br />(first (System/getProperties))<br />#<Entry java.runtime.name=OpenJDK Runtime Environment><br />(rest (.g...
Java Interops<br />Clojue Strings  == Java Strings<br />Clojure Numbers == Java Numbers<br />Clojure Collections实现java Col...
Java Interops实例<br />(. Math PI)   <br />Math/PI<br />(new java.util.Date) <br />(java.util.Date.)<br />(. date getYear)<b...
Persistent Data Structures<br />Clojure的数据结构都是immutable的<br />每次更新都将创建一个新的数据结构<br />复制的开销<br />解决方案:结构共享,Persistent数据结构<br...
Persistent Data Structures<br />28<br />
Persistent Data Structures<br />29<br />
Clojure的并发<br />并发的一个关键点在于如何管理可变状态(mutable states)<br />锁的方式:<br />直接引用可变状态<br />采用锁来保护<br />消息传递的方式:<br />将可变状态作为不可变的消息传递...
典型的OO方式<br />一致性需要用户来保证<br />31<br />
Clojure——间接引用<br />值不可变<br />取值需要经过deref<br />32<br />
四种模型<br />Ref、Atomic、Agent和ThreadLocal vars<br />协作/独立:状态是否与其他状态共同作用<br />同步/异步:状态的更新是同步还是异步<br />33<br />
Ref和事务<br />(def songs (ref #{}))<br />创建ref<br />@songs<br />取ref的值<br />(dosync (refset songs #{“dangerous”}))<br />改变re...
STM<br />使用(dosync …)包装<br />软事务内存,内存型数据库:ACI,没有D<br />基于MVCC实现——多版本并发控制<br />所有对ref的读都将在事务开始的时候“看到”一个一致的快照(Snapshot),以及该事...
Atomic<br />管理独立的可变状态,类似Java的AtomicReference(内部实现)<br />(def mem (atom {}))<br />创建atom<br />@meme<br />取值<br />(reset! me...
Agent<br />用于异步的状态更新<br />(def counter (agent 0))<br />创建agent<br />@counter<br />取值<br />(send counter inc)<br />发送任务,适合非...
Clojure的实现——函数<br />动态编译成bytecode<br />使用asm 3.0<br />暂时没有AOT编译模式<br />每个函数都是一个新的class<br />实现clojure.lang.IFn接口<br />根据函数...
Clojure的实现——调用<br />函数调用就是Java的方法调用<br />没有额外的类型系统和转换<br />没有额外的参数<br />对Java的调用:直接调用 or 反射<br />没有包装、捕获异常和动态转换<br />Type ...
Clojure的实现——STM<br />MVCC——Multiversion Concurrency Control<br />每个ref维持一张版本列表<br />事务开始和提交的时候都分配一个时间戳<br />提交成功的时候,将commi...
Clojure的实现——Atomic和Agent<br />Atomic,内部封装AtomicReference<br />Agent<br />全局线程池<br />send使用固定大小线程池 cpus+2<br />适合计算密集型任务<br...
没有谈到的……<br />函数的递归调用<br />let/fn/loop的destructuring<br />列表推断(Lisp comprehesions)<br />关系集合代数<br />Multimethods<br />并行计算(...
一些缺憾<br />没有尾递归优化<br />recur仅能在方法内,goto指令<br />受限于JVM的安全模型<br />所有JVM之上的函数式语言都有这个问题<br />使用Java数值类型的包装类型以及Cojure独有的Ratio<b...
参考资料<br />http://clojure.org/<br />http://clojuredocs.org/<br />不错的网络教程<br />clojure相关资料<br />我的Blog<br />书籍推荐:<br />44<br />
Thanks!<br />2010-08-10<br />淘宝内部分享-伯岩<br />45<br />
Upcoming SlideShare
Loading in...5
×

Clojure的魅力

7,873

Published on

内部分享,介绍clojure语言

Published in: Education
0 Comments
17 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
7,873
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
200
Comments
0
Likes
17
Embeds 0
No embeds

No notes for slide

Transcript of "Clojure的魅力"

  1. 1. Clojure的魅力<br />伯岩<br />boyan@taobao.com<br />2010-08-10<br />
  2. 2. Agenda<br />Clojure基础<br />Clojure语法和数据结构<br />Sequences<br />与java交互<br />并发<br />实现<br />缺陷<br />总结<br />2<br />
  3. 3. What is clojure?<br />A dynamic programming language for JVM<br />Clojure is a Lisp<br />Clojure is functional<br />Supporting Concurrency<br />Designed for the JVM<br />History<br />3 years in development,released 10/2007<br />Authror: Rich Hickey<br />Homepage: http://clojure.org<br />3<br />
  4. 4. Clojure is a Lisp<br />Clojure是Lisp的一种方言,就像scheme、common lisp也是Lisp的方言一样。<br />Clojure同样也是Homoiconicity(同像性)<br />Homoiconicity:编程语言的一种属性,是指该语言的基本表现形式本身同时也是该语言自身的数据结构。<br />Homoiconicity使得元编程更容易<br />Code vs. Data<br />小核心<br />Sequences抽象<br />宏(macro)<br />非OO模型<br />4<br />
  5. 5. Hello World<br />REPL——交互式编程环境<br />user=> (println "hello world")<br /> hello world<br /> nil<br />5<br />
  6. 6. Code vs. Data<br />从代码角度<br /> (println "hello world")<br />函数 参数<br /> 从数据角度<br /> (println "hello world")<br />一个list<br />6<br />
  7. 7. Clojure的数据类型<br />Integer –123456789<br />Double 1.234<br />BigDecimal 1.234m<br />Ratios(分数)22/7<br />Strings “hello”<br />Characters a  c<br />Symbols foo bar<br />Keywords :foo :bar<br />Booleans true false<br />Null nil<br />Regex patterns #“[a-z]*d+”<br />2010-08-10<br />淘宝内部分享-伯岩<br />7<br />
  8. 8. 数据结构<br />List单向链表<br />(1 2 3 4 5) (list a  c)<br />Vector类似数组,索引访问<br />[1 2 3 4 5] [foo bar]<br />Map key/value<br />{:a 1 :b 2} {1 “hello” 2 “world”}<br />Set集合,不能重复<br />#{foo bar}<br />全部可嵌套<br />2010-08-10<br />淘宝内部分享-伯岩<br />8<br />
  9. 9. 语法<br />前缀运算符<br />(+ 1 2 3) (println (str “hello “ “world”))<br />(op …), op可以为<br />少数几个special form<br />Macro<br />返回函数的表达式<br />数据结构即代码<br />语法 == 数据结构的解释<br />9<br />
  10. 10. 传统的求值模型<br />2010—8-10<br />淘宝内部分享-伯岩<br />10<br />
  11. 11. Clojure的求值模型<br />2010-08-10<br />淘宝内部分享-伯岩<br />11<br />
  12. 12. Symbols<br />可以理解成变量,绑定特定的值<br />user=> a<br /> java.lang.Exception: Unable to resolve symbol: a in this context (NO_SOURCE_FILE:0)<br />user=> (def a 1)<br /> #'user/a<br /> user=> a<br /> 1<br />user=> (let [a 1] a)<br /> 1<br />user=> (binding [a 2] a)<br /> 2<br />2010-08-10<br />淘宝内部分享-伯岩<br />12<br />
  13. 13. let和binding<br />let是用词法作用域的不可变值“遮蔽”了外部的symbol绑定值。<br />Binding则是创建thread-local级别的symbol绑定值。<br />例子:<br />(def foo 1)<br />(defn print-foo [] (println foo))<br />(let [foo 2] (print-foo)) =>1<br />(binding [foo 2] (print-foo)) =>2<br />2010-08-10<br />淘宝内部分享-伯岩<br />13<br />
  14. 14. Special forms<br />(def name init-value?) <br />定义全局变量<br />(if test then-expr else-expr)<br />条件语句<br />(quote form)<br />返回不会被执行的form<br />(fn name? ([params* ] exprs*)+)<br />定义函数<br />其他:let loop recur do new . throw try set! var<br />14<br />
  15. 15. Macro——宏<br />Macro是Clojure元编程的主要方式<br />什么是Macro?<br />模板语言<br />C语言的预处理器<br />unless:<br />(defmacro unless [test expr]<br /> `(if ~test nil ~expr))<br /> (if ${test} nil ${expr})<br />15<br />
  16. 16. Macro<br />`<br />Syntax quote 标记为模板<br />~<br />Unquote 替代value<br />~@<br />Splicing unquote 拼接list的内容<br />foo# <br />Auto-gensym 创建唯一符号名称<br />16<br />
  17. 17. 函数<br />Clojure是FP——函数式编程语言<br />函数是First-Class Values<br />作为参数<br />作为返回值<br />保存为变量<br />(def square (fn [x] (* x x)))<br /> (squre 3) => 9<br /> (defn square [x] (* x x))<br />17<br />
  18. 18. 高阶函数<br />18<br />
  19. 19. 高阶函数<br />以信息流的方式去组织代码,高阶函数带来了约定接口的抽象<br />19<br />range:<br />integers<br />map:<br />fib<br />filter:<br />even?<br />
  20. 20. 语法小结<br />20<br />
  21. 21. Sequences<br />传统Lisp中list的抽象<br />(cons item seq)<br />将item插入seq的首部创建新的seq<br />(seq coll)<br />如果集合为空,返回nil,否则返回集合的seq<br />(first seq) == (car list)<br />返回seq的第一个元素<br />(rest seq) == (cdr list)<br />返回seq除第一个元素之外的元组,如果没有则为nil<br />21<br />
  22. 22. Sequence(1)<br />22<br />
  23. 23. Sequence(2)<br />(iterate inc 0)<br />自然数集合<br />(use ‘[clojure.contrib.lazy-seqs :only(primes)])<br /> (def ordinals-and-primes (map vector (iterate inc 1) primes))<br />[1 2] [2 3] [3 5]…[n nth-primes]的vector集合<br />延迟和无穷<br />doall dorun 强制seq的副作用触发<br />23<br />
  24. 24. Sequence(3)<br />(first (System/getProperties))<br />#<Entry java.runtime.name=OpenJDK Runtime Environment><br />(rest (.getBytes “hello”))<br />(101 108 108 111)<br />(sort (re-seq #“w+” “the quick brown fox”))<br />(“brown” “fox” “quick” “the”)<br />(count (file-seq (File. ".")))<br />(with-open [rdr (reader “hello.clj”)]<br /> (count (line-seq rdr)))<br />TODO(xml-seq)<br />24<br />
  25. 25. Java Interops<br />Clojue Strings == Java Strings<br />Clojure Numbers == Java Numbers<br />Clojure Collections实现java Collection接口<br />Clojure函数实现Runnable和Callable接口<br />Clojure可以继承和实现Java的类和接口<br />Clojure的seq库可以直接使用在Java的String和Array以及Iterable<br />25<br />
  26. 26. Java Interops实例<br />(. Math PI) <br />Math/PI<br />(new java.util.Date) <br />(java.util.Date.)<br />(. date getYear)<br />(.getYear date)<br />(.. System getProperties (get “java.version”))<br />(doto (JFrame.) (add (Jlabel. “hello world”)) pack show)<br />(int-array 3)<br />(aset a 0 1) (aget a 0) (alength a)<br />26<br />
  27. 27. Persistent Data Structures<br />Clojure的数据结构都是immutable的<br />每次更新都将创建一个新的数据结构<br />复制的开销<br />解决方案:结构共享,Persistent数据结构<br />Git的tree结构<br />Couch DB的索引<br />Clojure的数据结构<br />27<br />
  28. 28. Persistent Data Structures<br />28<br />
  29. 29. Persistent Data Structures<br />29<br />
  30. 30. Clojure的并发<br />并发的一个关键点在于如何管理可变状态(mutable states)<br />锁的方式:<br />直接引用可变状态<br />采用锁来保护<br />消息传递的方式:<br />将可变状态作为不可变的消息传递<br />没有共享状态<br />Clojure的方式:<br />间接引用不可变的持久数据结构<br />STM更新状态<br />没有锁<br />30<br />
  31. 31. 典型的OO方式<br />一致性需要用户来保证<br />31<br />
  32. 32. Clojure——间接引用<br />值不可变<br />取值需要经过deref<br />32<br />
  33. 33. 四种模型<br />Ref、Atomic、Agent和ThreadLocal vars<br />协作/独立:状态是否与其他状态共同作用<br />同步/异步:状态的更新是同步还是异步<br />33<br />
  34. 34. Ref和事务<br />(def songs (ref #{}))<br />创建ref<br />@songs<br />取ref的值<br />(dosync (refset songs #{“dangerous”}))<br />改变ref指向的值,需要包装在事务里<br />(def singers (ref #{}))<br /> (dosync (ref-set sings #{“dangerous”})<br /> (ref-set singers #{“MJ”}))<br />协作更新多个ref<br />(dosync (alter songs conj “heal the world”))<br />查询并更新<br />(dosync (commute songs conj “heal the world”))<br />更新操作是可交换的,符合交换律<br />34<br />
  35. 35. STM<br />使用(dosync …)包装<br />软事务内存,内存型数据库:ACI,没有D<br />基于MVCC实现——多版本并发控制<br />所有对ref的读都将在事务开始的时候“看到”一个一致的快照(Snapshot),以及该事务内对ref所做的更改。<br />所有在事务内对ref所做的更改,在外部看来都将是一个时间点触发的。<br />读不会阻碍读/写,写不会阻碍读<br />没有死锁,活锁的隐患<br />35<br />
  36. 36. Atomic<br />管理独立的可变状态,类似Java的AtomicReference(内部实现)<br />(def mem (atom {}))<br />创建atom<br />@meme<br />取值<br />(reset! mem {:a 1})<br />设值,无需事务<br />(swap! mem assoc :b 2)<br />查询并更新<br />(compare-and-set! mem oldValue newValue)<br />原子的比较更新<br />适合实现缓存 memoize<br />36<br />
  37. 37. Agent<br />用于异步的状态更新<br />(def counter (agent 0))<br />创建agent<br />@counter<br />取值<br />(send counter inc)<br />发送任务,适合非阻塞任务<br />(send-off counter inc)<br />发送任务,适合阻塞型任务,如IO操作<br />(await counter)<br />等待任务结束<br />每个agent每次只执行一个任务,同一个线程发送的任务有序<br />可以在事务中使用,那么当且仅当事务commit成功的时候发送任务 实现bin log<br />37<br />
  38. 38. Clojure的实现——函数<br />动态编译成bytecode<br />使用asm 3.0<br />暂时没有AOT编译模式<br />每个函数都是一个新的class<br />实现clojure.lang.IFn接口<br />根据函数的参数个数实现对应的系列invoke方法<br />参数和返回值都以Object类型存在<br />可变参数基于sequences实现<br />Clojure Hacking Guide<br />38<br />
  39. 39. Clojure的实现——调用<br />函数调用就是Java的方法调用<br />没有额外的类型系统和转换<br />没有额外的参数<br />对Java的调用:直接调用 or 反射<br />没有包装、捕获异常和动态转换<br />Type hints和类型推断允许直接调用<br />(def class-name [^Class c]<br /> (.getName c))<br />*warn-on-reflection* 提示反射,避免反射<br />39<br />
  40. 40. Clojure的实现——STM<br />MVCC——Multiversion Concurrency Control<br />每个ref维持一张版本列表<br />事务开始和提交的时候都分配一个时间戳<br />提交成功的时候,将commit时间戳和新的值加入Ref的版本列表<br />Write Conflict<br />abort and retry<br />Barge<br />Commute,不做写冲突检查,不取得ref的ownership,计算立即可见,但是在commit的时候如果发现ref值被其他事务更改了,重新运行计算。<br />Software Transactional Memory<br />40<br />
  41. 41. Clojure的实现——Atomic和Agent<br />Atomic,内部封装AtomicReference<br />Agent<br />全局线程池<br />send使用固定大小线程池 cpus+2<br />适合计算密集型任务<br />send-off使用Cached ThreadPool<br />适合IO型任务<br />(shutdown-agents)<br />关闭线程池<br />41<br />
  42. 42. 没有谈到的……<br />函数的递归调用<br />let/fn/loop的destructuring<br />列表推断(Lisp comprehesions)<br />关系集合代数<br />Multimethods<br />并行计算(pmap pvalues pcalls)<br />……<br />2004-5-31<br />淘宝内部分享-烟客<br />42<br />
  43. 43. 一些缺憾<br />没有尾递归优化<br />recur仅能在方法内,goto指令<br />受限于JVM的安全模型<br />所有JVM之上的函数式语言都有这个问题<br />使用Java数值类型的包装类型以及Cojure独有的Ratio<br />Integer,Long,BigInteger etc.<br />数值在heap上,算术运算性能欠佳<br />Agent无法自定义线程池<br />线程没有命名,非daemon<br />无法高效利用线程池<br />弱类型,没有scala那样强大的类型推断能力,需要用户接入:type hint<br />括号复括号,FP,小众中的小众<br />43<br />
  44. 44. 参考资料<br />http://clojure.org/<br />http://clojuredocs.org/<br />不错的网络教程<br />clojure相关资料<br />我的Blog<br />书籍推荐:<br />44<br />
  45. 45. Thanks!<br />2010-08-10<br />淘宝内部分享-伯岩<br />45<br />
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×