Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Clojure的魅力

8,428 views

Published on

内部分享,介绍clojure语言

Published in: Education
  • Dating for everyone is here: ♥♥♥ http://bit.ly/2u6xbL5 ♥♥♥
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Follow the link, new dating source: ❤❤❤ http://bit.ly/2u6xbL5 ❤❤❤
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

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 />

×