The Joy of Clojure

跳转至: 导航、 搜索

目录

  • 1 基础
  • 2 Data types
  • 3 FP
  • 4 large-scale design
    • 4.1 Macros
    • 4.2 Combining data and code
    • 4.3 Java.next
    • 4.4 Mutation
  • 5 Tangential considerations

基础

  1. (for [x [:a :b], y (range 5) :when (odd? y)] [x y])

    1. for产生lazy seq
    2. :when :while是guard's
  2. Simplicity, freedom to focus, empowerment, consistency, and clarity.
  3. LISP: atom, car, cdr, cond, cons, eq, quote; lambda, label
  4. SQL DSL???
    1. ~:unquote
  5. Code is data
  6. FP?:Haskell, ML, Factor, Unlambda, Ruby, or Qi.
  7. OOP:no clear distinction between state and identity(状态 vs. 身份)
    1. defprotocol(定义接口)、extend-type(扩展类型)
  8. 关键字::keyword
  9. 容器类型:
    1. Lists:(yankee hotel foxtrot)

      1. 第一个元素:A form is any Clojure object meant to be evaluated ...
    2. Vectors:[1 2 :a :b :c]
    3. Maps(这里的语法很诡异):{1 "one", 2 "two", 3 "three"}
    4. Sets:#{1 2 "three" :four 0x5}
  10. 函数调用
    1. (+ 1 2 3)
  11. 定义函数
    1. (fn mk-set [x y] #{x y})

      1. ((fn [x y] #{x y}) 1 2) --匿名函数?

        1. 允许arity重载:(fn ([x] #{x}) ([x y] #{x y}))

          1. 变长参数:((fn arity2+ [x y & z] [x y z]) 1 2 3 4) ;=> [1 2 (3 4)] &后的参数以list传递
  12. special form
    1. 匿名函数?:fn
    2. 命名函数:def defn
    3. 顺序执行:do
    4. 尾递归:recur
    5. 条件:if(when,and,or是宏)
    6. 循环:loop(作为recur的跳转目标)。。。恩,recur相当于C语言里的goto了
    7. let(局部变量与`locals`有什么区别?):immutable
      (def make-a-set (fn ([x] #{x}) ([x y] #{x y}))) 相当于JavaScript里的var f = function(){ ... }
  13. In-place functions with #() 这里的记号似乎有点混淆?
    (def make-a-list_ #(list %)) ;为什么不是defn?
    (def make-a-list3+ #(list %1 %2 %3 %&))
  14. Vars
    1. (def x 42) ;这是root binding(全局变量?)
    2. 测试:(.start (Thread. #(println "Answer: " x)))
  15. Locals, loops, and blocks
    1. (let [x 1 y 2] (println (+ x y)))
    2. ...
  16. Preventing things from happening: quoting
    1. (cons 1 [2 3]) ;立即评估
    2. => (quote (cons 1 [2 3])) ;推迟评估
    3. (cons 1 (quote (2 3))) ???(评估过程对于LISP表达式是递归的函数调用吗?难怪没法区分)=> (cons 1 '(2 3))
    4. Syntax-quote:`(1 2 3) ;用于动态构造函数代码?
      1. clojure.core/map
      2. `能够做自动名字空间解开:`(map even? [1 2 3]) ;重名的情况怎么办? ... "will use the current namespace"
    5. unquote ~
      1. `(+ 10 ~(* 3 2))
    6. unquote-splicing(FP里的评估、bound/unbound概念真是麻烦!)
      1. (let [x '(2 3)] `(1 ~@x))
    7. Auto unqualified symbol:`potion#
  17. Java Interop(Java互操作)
    1. 静态方法调用:(Math/sqrt 9)
    2. 类实例:(new java.util.HashMap {"foo" 42 "bar" 9 "baz" "quux"})
      或(Clojure习俗):(java.util.HashMap. {"foo" 42 "bar" 9 "baz" "quux"})
    3. (.x (java.awt.Point. 10 20)) ;这相当于把一个成员方法作用于一个对象实例(函数调用的风格)
    4. (let [origin (java.awt.Point. 0 0)] (set! (.x origin) 15) ) ;这里的set!是通过反射调用的吗
    5. 调用链风格:..(Clojure里更习惯用->、->>)
      (.. (java.util.Date.) toString (endsWith "2010"))
    6. doto宏
  18. macros
    1. reify、deftype:创建Java接口的实现
    2. ns:名字空间
      (ns joy.req (:require clojure.set)) ;暂时无法理解这么做的原因?
      (ns joy.use-ex (:use [clojure.string :only [capitalize]])) ;仅将capitalize映射到当前名字空间。。。哦。。。
      :refer *
      (ns joy.java (:import [java.util HashMap] [java.util.concurrent.atomic AtomicLong]))
  19. 异常(暂略)
    1. 当发生异常时,(.printStackTrace *e)
  20. Truthiness
    1. []、()不同于nil
    2. 不要创建Boolean类型的对象!
    3. nil punning
    4. Destructuring(相当于Scala/Erlang里的模式匹配)
      1. e.g. (let [[f-name m-name l-name] guys-whole-name] (str l-name ", " f-name " " m-name))
      2. e.g. (let [[a b c & more] (range 10)] ... )
      3. 匹配Map:(let [{f-name :f-name, m-name :m-name, l-name :l-name} guys-name-map]
      4. associative destructuring???
        (let [{first-thing 0, last-thing 3} [1 2 3 4]] [first-thing last-thing])
  21. (for [x (range 2) y (range 2)] [x y]) ;这个2重循环的写法真怪异

Data types

  1. M后缀:任意精度。(let [imadeuapi 3.14159265358979323846264338327950288419716939937M] ...
  2. Promotion(自动的精度提升):如何检测‘溢出’的?(class (+ clueless 90000000000000000000))
  3. Rounding errors
  4. 表达式中有一个是double,结果就是double???(+ 0.1M 0.1M 0.1M 0.1 0.1M 0.1M 0.1M 0.1M 0.1M 0.1M)
  5. 使用有理数?
    1. BigDecimal用一个32位数表示小数点后的位数,。。。
    2. 浮点数不满足结合律于分配律(st!)
    3. (def b (rationalize -1.0e50))
  6. keywords vs. symbols
    1. (identical? 'goat 'goat) 与 (= 'goat 'goat)

      为什么不把相同的symbols存储到同一个'位置'?... metadata

      (let [x (with-meta 'goat {:ornery true}) y (with-meta 'goat {:ornery false})] ...
  7. Lisp-1:uses the same name resolution for function and value bindings,name-shadowing问题
    1. vs Lisp-2:依赖于context
    2. (defn best [f xs] (reduce #(if (f % %2) % %2) xs)) ~~~寒
  8. 正则表达式:#"an example pattern"
    1. 区别:(java.util.regex.Pattern/compile "\\d")等于#"\d"
    2. Regex flags:d i(不区分大小写) x m s u,例如:#"(?i)yo"
    3. (seq (.split #"," "one,two,three"))与(re-seq #"\w+" "one-two/three")
    4. !!!不要使用Matcher对象(re-matcher)
  9. Clojure’s sequence abstraction — all the persistent collections use it
  10. `persistent`:所有历史版本保留
    1. (def ds [:willie :barnabas :adam]) ==>修改:(def ds1 (replace {:barnabas :quentin} ds)) ;Scala风格

      变成可变的:(def ds (into-array [:willie :barnabas :adam])) ==>修改:(aset ds 1 :quentin)
  11. 比较sequential, sequence, and seq:
    1. sequential:元素顺序不会reordering
    2. sequence:seq操作返回,可在上执行first、rest操作(这里的命名与Lisp不太一致)
    3. (= [1 2 3] '(1 2 3))返回true,因为=操作基于序列接口?
  12. Vectors:immutable and persistent(arrays可变)
    1. (let [my-vector [:a :b :c]] (into my-vector (range 10))) ;‘倒进’操作 -- 这些名字太难记了!
    2. 相对与Lists更有效率的地方:从右边添加/删除元素;按索引访问;反向遍历
    3. (def a-to-j (vec (map char (range 65 75)))):
      1. (nth a-to-j 4) ;vector空或index越界时返回nil
      2. (get a-to-j 4) ;index越界时抛出异常
      3. (a-to-j 4)  ;会抛出异常(这里用法类似于Pyhton/C++?)
    4. 多维索引访问:get-in assoc-in update-in
    5. Vectors as stacks:conj/pop(靠,这个命名。。。);clojure.lang.IPersistentStack
    6. 经典的Lisp总是要求list翻转操作,但idiomatic Clojure使用vector就不需要(-_-)
    7. Subvectors:subvec操作,参数意义:[start, end)
    8. 作为MapEntry使用(实际上就是C++ hashmap的pair<K,V>)
  13. Lists: Clojure’s code form data structure
    1. (cons 1 '(2 3))与(conj '(2 3) 1)
    2. Clojure has no “dotted pair.” If you don’t know what that is, don’t worry about it.(这话真操蛋)
    3. peek/pop粗糙地等于first/rest(靠,作者似乎对程序的操作语义极为关注。。。但是一般的使用很容易混淆。。。)
    4. contains? will always return false for a list. ;既然不支持set接口,干吗要定义这个操作?
  14. 队列
    1. not a workflow mechanism(java.util.concurrent.BlockingQueue)
    2. clojure.lang.PersistentQueue/EMPTY
    3. 内部实现:the front being a seq and the rear being a vector(类似于一个C++ rope?)
  15. Persistent sets
    1. (sorted-set :b :c :a)
    2. Sets are implemented as maps with the same element as the key and value,。。。
  16. Thinking in maps
    1. key,value不要求同一类型:(let [m {:a 1, 1 :b, [1 2 3] "4 5 6"}] ...
    2. (map,key)可以视为函数调用。。。
    3. (into {} [[:a 1] [:b 2]]) ;返回一个相同结构的map对象
    4. (apply hash-map [:a 1 :b 2]) ;=> {:a 1, :b 2}
    5. (sorted-map :thx 1138 :r2d 2) ;支持key的有序遍历?(干吗不定义tree数据结构呢)
    6. 按照插入顺序:(seq (array-map :a 1, :b 2, :c 3))
  17. It’s usually a bad idea to build your programs around concrete types, and always bad to build around undocumented behaviors.

FP

  1. Equality in the presence of mutability has no meaning.

    1. And if two objects aren’t equal forever, then they’re technically never equal (Baker 1993). 哈哈
  2. lazy-seq原则:
    1. 使用lazy-seq宏
    2. rest,而不是next(重启,不是迭代)//Using next causes a lazy seq to be one element less lazy(因为需要检查‘下一个’)
    3. 为产生rest,仅仅保存必须的状态(相当于保存了一个函数对象?),避免过早的realize
    4. ??(let [r (range 1e9)] [(first r) (last r)]) ;=> [0 999999999]
    5. map,reduce,filter
    6. delay,force宏:不要直接使用,容易出错。。。?
      1. (if-let [res :truthy-thing] (println res)) ;另外的when-let
    7. *A lazy, tail-recursive quicksort implementation //看起来可以用它来求max/min-N?
  3. (def fifth (comp first rest rest rest rest))
  4. (defn fnth [n]
    (apply comp

    (cons first

    (take (dec n) (repeat rest)))))
  5. partial isn't currying. ?
    1. Because Clojure allows functions of variable number of arguments, currying makes little sense
  6. Higher-order functions:以函数为参数、返回值
  7. pure functions:相同输入总是得到相同输出;没有副作用
    1. ... as constant, or referentially transparent:例,(defn manip-map [f ks m] (conj m (keys-apply f ks m)))

      keys-apply: (defn keys-apply [f ks m] (let [only (select-keys m ks)] (zipmap (keys only) (map f (vals only)))))
  8. 命名参数:(defn slope [& {:keys [p1 p2] :or {p1 [0 0] p2 [1 1]}}] ... ;(slope :p1 [4 15] :p2 [3 21])
  9. :pre :post
  10. closure
    1. polymorphism
    2. compile-time VS run-time
      1. In current versions of Clojure, each function definition gets its own class.
  11. mundane recursion(显示的递归调用)
    1. 计数器+recur
    2. lazy-seq
    3. Scheme(Lambda Papers, Guy L. Steele and Gerald Sussman):actors被移除,仅保留functions => Generalized tail-call optimization
      任何A到B的尾调用将释放A下的locals ...
    4. JVM不提供lco机制,recur也只能处理自己调自己的特殊情形
      但至少Clojure为什么不在编译器层次把自己调自己的mundane recursion解析处理成recur呢?
  12. Tail position:
      1. fn, defn:(fn [args] expressions tail)
      2. loop:(loop [bindings] expressions tail)
    1. *...act as anonymous recursion points. Why recur indeed. (靠!)
  13. mutually recursive:trampoline??
  14. Continuation-passing style(CPS):1)必须保证bounded execution path;2)isn’t conducive to parallelization
    1. An accept function that decides when a computation should terminate
    2. A return continuation that’s used to wrap the return values
    3. A continuation function used to provide the next step in the computation
  15. e.g. A-* path-finding

large-scale design

Macros

  1. (-> 25 Math/sqrt int list):展开为(list (int (Math/sqrt 25)))
  2. (eval '(list 1 2))
  3. defmacro
    1. (defmacro resolution [] `x) => (macroexpand '(resolution)) ;Common LISP中需避免名字捕捉
  4. domain DSL structure ~ XML/JSON(都是树形结构)
  5. Anaphora(上下文的代词引用)
    1. Scala:Array(1, 2, 3, 4, 5).map(2 * _)
    2. Anaphora don’t nest, and as a result are generally not employed in Clojure.
    3. => if-let when-let ~'symbol
  6. selective name capturing
    1. proxy ~'this
    2. A hygienic macro is one that doesn’t cause name capturing at macro expansion time.(FUCK,学术气味太浓了吧?)
  7. 管理资源(try/catch/finally):with-open
    (defmacro with-resource [binding close-fn & body]

    `(let ~binding

    (try

    (do ~@body)
    (finally

    (~close-fn ~(binding 0))))))
  8. macros returning functions
  9. contract

Combining data and code

  1. ns:java.lang、clojure.core自动导入
  2. in-ns:不自动导入clojure.core
  3. create-ns
  4. ns-map
  5. Var mapping::exclude, :only, :as, :refer-clojure, :import, :use, :load, :require.
  6. Yegge’s UDP:beget, get, put, has?, forget
  7. Multimethods
    1. defmulti defmethod
    2. derive(继承关系?)
    3. prefer-method 解决多继承情况下的冲突?
    4. juxt
  8. Records
    1. (defrecord TreeNode [val l r])
  9. Protocols
    1. In fact, the first parameter to a protocol function corresponds to the target object ...
    2. Clojure-style mixins

Java.next

  1. proxy

    1. construct-proxy、get-proxy-class、init-proxy、update-proxy、
  2. gen-class
    1. (doto (StringBuilder. "abc") (.append (char-array [\x \y \z])))
    2. into-array ;type based on the first element of the sequence
    3. ... Instead, variadic methods expect an array as their final argument
  3. All Clojure functions implement...
    1. java.util.Comparator
    2. java.lang.Runnable
    3. java.util.concurrent.Callable
  4. Java里调用Clojure数据结构
    1. Clojure sequential collections conform to the immutable parts of the java.util.List
    2. java.util.List
    3. java.lang.Comparable
    4. java.util.RandomAccess
    5. java.util.Collection
    6. java.util.Set
  5. definterface
    1. (definterface ISliceable (slice [^int s ^int e]) (^int sliceCount []))

      (def dumb (reify user.ISliceable (slice [_ s e] [:empty]) (sliceCount [_] 42)))
  6. defprotocol ?
    1. extend
  7. extend-type
  8. 为了调用checked Exception的Java方法,Clojure中的所有函数都throws Exception ... ?
  9. Runtime versus compile-time exceptions
    1. (defn explode [] (explode)) ==> (try (explode) (catch Exception e "Stack is blown"))
    2. In Java, catching exceptions at the level of Throwable is considered bad form
    3. The way to throw a compile-time exception is to make sure your throw doesn’t occur within a syntax-quoted form
  10. (defmacro -?> [& forms]
    `(try (-> ~@forms)

    (catch NullPointerException _# nil)))
  11. ... then bear in mind that it’s rare for Clojure core functions to throw exceptions

Mutation

  1. A tangled web of mutation means that any change to your code potentially occurs in the large.
  2. 4 major mutable references: Refs, Agents, Atoms, and Vars.
  3. parallelism support: futures, promises, and a trio of functions pmap, pvalues, and pcalls
  4. STM with MVCC & snapshot isolation
    1. Time, State, Identity
    2. Clojure has but one transaction per thread, ...
      1. when a restart occurs in the (conceptual) subtransaction clojure.b, it causes a restart of the larger transaction.
    3. orphaned locks (locks held by a thread that has died)
    4. Any I/O operation in the body of a transaction is highly discouraged. ?事务不带外部磁盘IO怎么做?logging?
      1. (io! (.println System/out "Haikeeba!")) ;警告
      2. get in and get out as quickly as possible.
  5. When to use Refs
    1. ideal use:CoordinatedRetriable

      1. 其他:Agent:Asynchronous;Atom:Retriable;Var:Thread-local
    2. Coordinated: reads and writes to multiple refs can be made in a way that guarantees no race conditions
    3. Value access via the @ reader feature or the deref function
    4. 可绑定set-validator
    5. [脚注] Except for ref-set on Refs, reset! on Atoms, and set! on Vars. ???
    6. alter
    7. (stress-ref (ref 0 :min-history 15 :max-history 30))
  6. When to use Agents
    1. Each Agent has a queue to hold actions that need to be performed on its value
    2. 串行IO?(def log-agent (agent 0)) ...
    3. the current state of an Agent can be observed cheaply
    4. send
    5. send-off
    6. 错误处理::continue and :fail
      1. (restart-agent log-agent 2500 :clear-actions true)
  7. When to use Atoms
    1. Once an Atom’s value is set, it’s set, and it doesn’t roll back when a transaction is retried
    2. ... holding a function’s memoization cache is idempotent on update
    3. memoize
  8. When to use locks
  9. When to use futures(`one way to perform parallel computation`)
    1. (time (let [x (future (do (Thread/sleep 5000) (+ 41 1)))] [@x @x]))
  10. When to use promises
    1. placeholders for values whose construction is fulfilled by another thread via the deliver function
    2. Promises are write-once; any further attempt to deliver will throw an exception
    3. *A macro for transforming a callback-based function to a blocking call
    4. ?Deterministic deadlocks
  11. Parallelism
    1. as-futures与with-promises
    2. pvalues:it returns a lazy sequence of the results of all the enclosed expressions,例如:(pvalues 1 2 (+ 1 2))
    3. pmap
    4. pcalls
  12. Vars and dynamic binding
    1. binding宏
    2. def defn defmacro defonce defmulti defdynamic*
    3. (resolve 'x)、(bound? #'x)、(thread-bound? #'x)
    4. *with-local-vars、deref、var-get
    5. Dynamic scope(全局变量?)
    6. (with-precision 4
      (doall (map (fn [x] (/ x 3)) (range 1M 4M)))) #强制map解析
    7. bound-fn ?

Tangential considerations

  1. Performance:

    1. Type hints
    2. Transients
    3. Chunked sequences
    4. Memoization
    5. Understanding coercion

The Joy of Clojure 笔记相关推荐

  1. The Joy of Clojure – Clojure philosophy(1)

    The Clojure way Simplicity, 简约 It's hard to write simple solutions to complex problems. But every ex ...

  2. 《程序员的呐喊》一一1.6 神秘机器的笔记

    本节书摘来自异步社区出版社<程序员的呐喊>一书中的第1章,第1.6节,作者:[美]Steve Yegge ,更多章节内容可以访问云栖社区"异步社区"公众号查看. 1.6 ...

  3. Clojure 入门

    我将尝试教一些人(主要是Python开发者,在OS X操作系统运行)如何使用Clojure, 因为我觉得目前已经存在的一些教人如何从零开始学习Clojure的文档不尽如人意. 当我自己在几个月前亲身经 ...

  4. RDBMS vs. NoSQL Clojure概述

    RDBMS vs. NoSQL 合作还是竞争 数据库要解决的主要问题 不管是RDBMS还是NoSQL,在大的方面他们都属于数据库这个范畴,这个范畴之内所要面临的一些共同问题有哪些呢.下面的图是一个大致 ...

  5. clojure_深入了解Clojure系列

    clojure InfoQ读者可以 使用结帐代码" infoq35", 获得任何版本的 < Clojure的喜悦> (早期阅读电子书,或早期阅读电子书+印刷书)的 35 ...

  6. 每个程序员都应该知道的8个Linux命令

    为什么80%的码农都做不了架构师?>>>    摘要:Linux里有很丰富的各种命令,有些是很难用的.然而,学会了前面说的这8个命令,你已经能处理大量的log分析任务了,完全不需要用 ...

  7. 程序员需要知道的8个Linux命令

    每个程序员,在职业生涯的某个时刻,总会发现自己需要知道一些Linux方面的知识.我并不是说你应该成为一个Linux专家,我的意思是,当面对linux命令行任务时,你应该能很熟练的完成.事实上,学会了下 ...

  8. Java!越来越像Kotlin了!!

    作者 | The Bored Dev 译者 | 张卫滨 策划 | 蔡芳芳 来自不同编程语言的竞争正促使 Java 不断吸收新特性,变得更能适应时代和开发人员的新需求. 本文最初发表于 The Bore ...

  9. Java 二十五载,正在 Kotlin 化!

    相比 Groovy.Scala.Clojure 等来说,Kotlin 保留了 Java 所有的优点,消除了 Java 存在的大部分问题.这是它为什么如此受欢迎的主要原因,许多人认为它可以在未来几年取 ...

最新文章

  1. 5图片展示_做跨境电商想拍出爆款产品图片,我只用这五招
  2. DreamWeaver做ASP 第5页
  3. CodeForces - 1137B Camp Schedule(KMP的next数组+构造)
  4. python的request请求401_Python模拟HTTPS请求返回HTTP 401 unauthorized错误
  5. 【Python】PyMuPDF模块将PDF转换为图片
  6. 为什么iPhone 11在中国市场需求较美国强劲?真相扎心...
  7. java的printf语法_Java中printf的用法总结
  8. 根据交换方式可以把交换机划分为3种:存储转发交换、直通式交换、碎片过滤式交换
  9. puppet详解(八)——puppet自动化
  10. 【图论】【二分图匹配】[POJ 3041]I'm Telling the Truth
  11. 【验证码识别】OpenCV挑战顶象滑动拼图验证码
  12. python实现逻辑回归算法
  13. 【PPT】幻灯片放映中常用快捷键
  14. 《 人机交互技术》第三章 交互设备
  15. 【旧资料整理】不用FlashGot 让迅雷支持firefox3
  16. R语言中 attach()与detach(),及with()的使用
  17. 一点笔记,好记性不如烂笔头
  18. 生鲜配送APP软件开发快速制作
  19. 纪中9日游(2019.7.5~7.13)
  20. Linux高级命令进阶(week1_day2)--技术流ken

热门文章

  1. 毕业设计-基于JavaWeb实现就业管理系统
  2. java 构造方法特点_简述 Java 中构造方法 的概念及特点。_市场营销知识答案_学小易找答案...
  3. Intro to Deep Learning Backpropagation 深度学习模型介绍及反向传播算法推导详解
  4. 临沂中考计算机试题,临沂市中考信息技术操作题指导
  5. OC 7141采用 SOT-23-5 封装,电源电压: 2.5V~6V,线性降压恒流驱动器
  6. 挑战杯大赛优秀作品示例_图像分类比赛tricks:华为云人工智能大赛·垃圾分类挑战杯...
  7. linux下iostat命令无效,iostat命令详解
  8. 区域生长算法 python代码_区域生长Python
  9. Android设置控件背景颜色
  10. outlook2013邮箱找不到服务器,Outlook2013收件箱不显示邮件的解决方法