阿小信大人的头像
Life is short (You need Python) Bruce Eckel

clojure-koans练习笔记2016-05-19 12:09

strings笔记

get使用姿势

get returns a value mapped to key, not-found or nil if not present. So to get \C we have to pass in the index 0.

koan-engine.runner=> (get "asd" 0)
\a
koan-engine.runner=> (get "asd" 1)
\s
koan-engine.runner=> (get "asd" -1)
nil
koan-engine.runner=> (get "asd" -1 \X)
\X
(get [1 2 3] 1)
2
(get {:a 1 :b 2} :b)
2

在clojure中""里面的才是字符串,字符是有\开头的一个字符。

koan-engine.runner=> (type \q)
java.lang.Character
koan-engine.runner=> (type "q")
java.lang.String

subs截取字符串

(= "World" (subs "Hello World" 6 11))

; (subs s start) (subs s start end)
; Returns the substring of s beginning at start inclusive, and ending
; at end (defaults to length of string), exclusive.

lists笔记

cons使用姿势

(= '(:a :b :c :d :e) (cons :a '(:b :c :d :e)))
;; Returns a new seq where x is the first element and seq is the rest.
;; prepend 1 to a list
; (cons 1 '(2 3 4 5 6))
;;=> (1 2 3 4 5 6)

;; notice that the first item is not expanded
; (cons [1 2] [4 5 6])
;;=> ([1 2] 4 5 6)

conj使用姿势

(= '(:e :a :b :c :d) (conj '(:a :b :c :d) :e))
;; notice that conjoining to a vector is done at the end
; (conj [1 2 3] 4)
;;=> [1 2 3 4]

;; notice conjoining to a list is done at the beginning
; (conj '(1 2 3) 4)
;;=> (4 1 2 3)

; (conj ["a" "b" "c"] "d")
;;=> ["a" "b" "c" "d"]

;; conjoining multiple items is done in order
; (conj [1 2] 3 4)
;;=> [1 2 3 4]

; (conj '(1 2) 3 4)
;;=> (4 3 1 2)

; (conj [[1 2] [3 4]] [5 6])
;;=> [[1 2] [3 4] [5 6]]

;; conjoining to maps only take items as vectors of length exactly 2
; (conj {1 2, 3 4} [5 6])
;;=> {5 6, 1 2, 3 4}

; (conj {:firstname "John" :lastname "Doe"} {:age 25 :nationality "Chinese"})
;;=> {:nationality "Chinese", :age 25, :firstname "John", :lastname "Doe"}

;; conj on a set
; (conj #{1 3 4} 2)
;;=> #{1 2 3 4}

;; conjoin nil with x or xs
; (conj nil 3)
;;=> (3)

; (conj nil 3 4)
;;=> (4 3)

maps笔记

assoc使用姿势

(= {1 "January" 2 "February"} (assoc {1 "January"} 2 "February"))
; assoc 表示 associate 的意思。
; assoc 接受一个 Map ,还有一个或多个 key-val 对, 返回一个和传入 Map 类型相同的新 Map , 除了原来传入 Map 已有的数据外, 新 Map 还包含传给 assoc 的那些 key-val 对。
; 当一个向量被应用到 assoc 函数时, 返回一个新向量, 新向量的索引下标(index) key 的值就是 val 。
; 注意索引下标必须 <= (count vector) 。
; user=> (assoc {} :Clojure "Rich")
; {:Clojure "Rich"}
; user=> (assoc {:Clojure "Rich"} :Clojure "Rich Hickey")     ; 如果有同名 key ,那么那么覆盖它
; {:Clojure "Rich Hickey"}
; user=> (assoc [1 2 3] 0 10086)
; [10086 2 3]
; user=> (assoc [1 2 3] 3 10086)          ; key 最大可以等于 (count vector)
; [1 2 3 10086]
; user=> (assoc [1 2 3] 10086 10086)      ; key 不能大于 (count vector)
; IndexOutOfBoundsException   clojure.lang.PersistentVector.assocN
; (PersistentVector.java:136)

functions笔记

匿名函数使用姿势

(= 60 (#(* 15 %) 4))
; These are anonymous functions. The hash and parenthesizes will denote an anonymous function.
; Anywhere you see a percentages sign, they are the passed in values.

(= 9 (((fn [] #(+ % %2))) 4 5))
;    ^^^定义一个返回值为匿名函数的匿名函数
;    ||执行外层的匿名函数,返回#()定义的匿名函数
;    |执行返回的那个匿名函数 并传递4 5两个参数
; magic

(= 25 (#(% 5) square)))
; (= 25 ((fn [f] (f 5)) square)))

conditionals笔记

(let [x 5]
    (= :your-road (cond (= x 2) :road-not-taken
                        (= x 3) :another-road-not-taken
                        :else :your-road)))
; :else is not special. any non-nil or true will work.
; koan-engine.runner=> (let [x 5] (cond (= x 2) :road-not-token (= x 3) :another-road-not-taken :666 :your-road))
; :your-road
; koan-engine.runner=> (let [x 5] (cond (= x 2) :road-not-token (= x 3) :another-road-not-taken :default :your-road))
; :your-road

higher_order_functions笔记

reduce使用姿势

(= 2400 (reduce (fn [a b] (* a b)) 100 [1 2 3 4]))
; clojure.core/reduce
; ([f coll] [f val coll])
;   f should be a function of 2 arguments. If val is not supplied,
;   returns the result of applying f to the first 2 items in coll, then
;   applying f to that result and the 3rd item, etc. If coll contains no
;   items, f must accept no arguments as well, and reduce returns the
;   result of calling f with no arguments.  If coll has only 1 item, it
;   is returned and f is not called.  If val is supplied, returns the
;   result of applying f to val and the first item in coll, then
;   applying f to that result and the 2nd item, etc. If coll contains no
;   items, returns val and f is not called.

creating_functions笔记

complement使用姿势

(= [true false true] (let [not-a-symbol? (complement symbol?)]
                (map not-a-symbol? [:a 'b "c"])))
; (complement f)
; Takes a fn f and returns a fn that takes the same arguments as f,
; has the same effects, if any, and returns the **opposite** truth value.
; koan-engine.runner=> (not (zero? 0))
; false
; koan-engine.runner=> ((complement zero?) 0)
; false

partial使用姿势

(= 20 (let [multiply-by-5 (partial * 5)]
        (multiply-by-5 4)))
; (def subtract-from-hundred (partial - 100))
; user=> (subtract-from-hundred 10)      ; same as (- 100 10)
; 90
; user=> (subtract-from-hundred 10 20)   ; same as (- 100 10 20)
; 70

comp使用姿势

(= 25 (let [inc-and-square (comp square inc)]
        (inc-and-square 4)))
; 组合函数comp: 形如   ((comp f1 f2 .. fn) arg1 arg2 .. argn)
; 就是对参数从右到左组合执行所有函数,可以转变为: (f1 (f2 (.. (fn arg1 arg2 .. argn))))

refs笔记

一篇不错的讲ref的文章:http://wuchong.me/blog/2015/11/06/learn-clojure-3-concurrent/

macros笔记

相关文章http://www.isnowfy.com/clojure-macro/

defmacro的作用就是在代码编译的时候,会把defmacro当作是函数运行一次,并且把这个的返回结果替换到原有的位置上去

`表示syntax quote,'表示quote,~表示unquote,~@表示unquote splicing。

如果某段代码前面加了'就表示这段代码被quote而不会去求值了,而`的syntax quote则表示会把相应的变量变成有namespace的形式

~和是搭配使用的,~必须在的后面,并且~的数量不能超过`的数量,~是用来将变量的值替换到相应位置

而~@的作用和~类似,不过~@不但会替换掉值并且会把值打撒。

datatypes笔记

Clojure Tip: defstruct, deftype, defrecord: http://www.thejach.com/view/2011/09/clojure_tip_defstruct_deftype_defrecord

partition笔记

(= '((:a :b :c)) (partition 3 [:a :b :c :d :e]))

; partition demo
;; partition a list of 20 items into 5 (20/4) lists of 4 items
(partition 4 (range 20))
;;=> ((0 1 2 3) (4 5 6 7) (8 9 10 11) (12 13 14 15) (16 17 18 19))

;; partition a list of 22 items into 5 (20/4) lists of 4 items
;; the last two items do not make a complete partition and are dropped.
(partition 4 (range 22))
;;=> ((0 1 2 3) (4 5 6 7) (8 9 10 11) (12 13 14 15) (16 17 18 19))

;; uses the step to select the starting point for each partition
(partition 4 6 (range 20))
;;=> ((0 1 2 3) (6 7 8 9) (12 13 14 15))

;; if the step is smaller than the partition size, items will be reused
(partition 4 3 (range 20))
;;=> ((0 1 2 3) (3 4 5 6) (6 7 8 9) (9 10 11 12) (12 13 14 15) (15 16 17 18))

;; when there are not enough items to fill the last partition, a pad can be supplied.
(partition 3 6 ["a"] (range 20))
;;=> ((0 1 2) (6 7 8) (12 13 14) (18 19 "a"))

;; when a pad is supplied, the last partition may not be of the same size as the rest
(partition 4 6 ["a"] (range 20))
;;=> ((0 1 2 3) (6 7 8 9) (12 13 14 15) (18 19 "a"))

;; but only as many pad elements are used as necessary to fill the final partition.
(partition 4 6 ["a" "b" "c" "d"] (range 20))
;;=> ((0 1 2 3) (6 7 8 9) (12 13 14 15) (18 19 "a" "b"))

;; a step smaller than the partition-size results in reuse.
(partition 3 1 [:a :b :c :d :e :f])
;;=> ((:a :b :c) (:b :c :d) (:c :d :e) (:d :e :f))

;; When there are less than n items in the coll, partition's behaviour
;; depends on whether there is a pad or not

;; without pad
(partition 10 [1 2 3 4])
;;=> ()

;; again, without pad
(partition 10 10 [1 2 3 4])
;;=> ()

;; with a pad this time (note: the pad is an empty sequence)
(partition 10 10 nil [1 2 3 4])
;;=> ((1 2 3 4))

;; or, explicit empty sequence instead of nil
(partition 10 10 [] [1 2 3 4])
;;=> ((1 2 3 4))

group-by笔记

group-by使用姿势

;; group strings by their length
(group-by count ["a" "as" "asd" "aa" "asdf" "qwer"])
;;=> {1 ["a"], 2 ["as" "aa"], 3 ["asd"], 4 ["asdf" "qwer"]}

;; group integers by a predicate
(group-by odd? (range 10))
;;=> {false [0 2 4 6 8], true [1 3 5 7 9]}

;; group by a primary key
(group-by :user-id [{:user-id 1 :uri "/"}
                    {:user-id 2 :uri "/foo"}
                    {:user-id 1 :uri "/account"}])

;;=> {1 [{:user-id 1, :uri "/"}
;;       {:user-id 1, :uri "/account"}],
;;    2 [{:user-id 2, :uri "/foo"}]}

juxt使用方式

((juxt a b c) x) => [(a x) (b x) (c x)]

meta笔记

with-metameta使用姿势

(def giants
  (with-meta 'Giants
    {:league "National League"}))

; (with-meta obj m)
; Returns an object of the same type and value as obj, with map m as its metadata.

; (meta obj)
; Returns the metadata of obj, returns nil if there is no metadata.

Metadata Reader Macros:

^{:doc "How obj works!"} obj - Sets the metadata of obj to the provided map. Equivalent to (with-meta obj {:doc "How obj works!"})

^:dynamic obj - Sets the given keyword to true in the object’s metadata. Equivalent to ^{:dynamic true} obj

^String obj - Sets the value of :tag key in the object’s metadata. Equivalent to ^{:tag java.lang.String} obj

(= {:division "West"} (meta '^{:division "West"} Giants))

merge

; (merge {:a 1 :b 2 :c 3} {:b 9 :d 4})
; ;;=> {:d 4, :a 1, :b 9, :c 3}
; (merge {:a 1} nil)   ;=> {:a 1}
; (merge nil {:a 1})   ;=> {:a 1}
; (merge nil nil)      ;=> nil
"Notice when metadata carries over"
(= {:foo :bar} (meta (merge '^{:foo :bar} {:a 1 :b 2}
                    {:b 3 :c 4})))

"And when it doesn't"  ;merge不会拿meta信息 第一个map没有meta,从第二个拿的时候不会带上第二个的meta
(= nil (meta (merge {:a 1 :b 2}
                    '^{:foo :bar} {:b 3 :c 4})))

vary-meta

"You can also create a new object from another object with metadata"
(= {:league "National League" :park "AT&T Park"}
    (meta (vary-meta giants
                    assoc :park "AT&T Park")))
; (vary-meta obj f & args)
; Returns an object of the same type and value as obj, with
; (apply f (meta obj) args) as its metadata.

"But it won't affect behavior like equality"  ;;; Zzzz why not {}
(= 'Giants (vary-meta giants dissoc :league))

pr-str

(= "Giants" (pr-str (vary-meta giants dissoc :league))))
; (pr-str & xs)
; pr to a string, returning it
; user=> (def x [1 2 3 4 5])
; #'user/x
; user=> x
; [1 2 3 4 5]

; ;; Turn that data into a string...
; user=> (pr-str x)
; "[1 2 3 4 5]"

; ;; ...and turn that string back into data!
; user=> (read-string (pr-str x))
; [1 2 3 4 5]

; ;; you can think of pr-str as the inverse of read-string
; ;; turn string into symbols
; user=> (read-string "(a b foo :bar)")
; (a b foo :bar)

; ;;turn symbols into a string
; user=> (pr-str '(a b foo :bar))
; "(a b foo :bar)"

如果您觉得从我的分享中得到了帮助,并且希望我的博客持续发展下去,请点击支付宝捐赠,谢谢!

若非特别声明,文章均为阿小信的个人笔记,转载请注明出处。文章如有侵权内容,请联系我,我会及时删除。

#Clojure#  
分享到:
阅读[803] 评论[0]

本文最近访客

发表评论