• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
Clojure #2
 

Clojure #2

on

  • 399 views

 

Statistics

Views

Total Views
399
Views on SlideShare
399
Embed Views
0

Actions

Likes
0
Downloads
6
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    Clojure #2 Clojure #2 Presentation Transcript

    • Clojure #2
    • Functional collections
    • map Для преобразования всех элементов коллекции можно использовать обычную функцию map: (defn fun [i] (+ 1 i)) (map fun [1 2 3])
    • mapcat Аналогично flatMap в Scala, в Clojure есть mapcat. (defn fun[i] (repeat i i)) (mapcat fun [1 2 3]) Получится (1 2 2 3 3 3)
    • filter and remove Две по сути одинаковые функции, только отличаются условием предиката (filter even? (1 2 3 4)) ;(2 4) (remove even? (1 2 3 4)) ;(1 3)
    • reduce Это тоже самое, что и foldLeft. Есть вариант, где первый элемент становится начальным значением или что-то другое: (reduce + [1 2 3]) ;6 (reduce cons '() [1 2 3]) ; (3 2 1)
    • reductions Это reduce, который сохраняет все промежуточные значения (reductions + [1 2 3]) ; (1 3 6)
    • Recursion
    • Simple recursion Просто можно вызвать функцию из тела: (defn sum [[head & tail]] (if (nil? head) 0 (+ head (sum tail)))
    • mutual recursion Иногда нужно, чтобы две функции умели друг друга вызывать, на помощь приходит declare для второй функции. (declare fun-2) (defn fun-1 [i] (if (< i 3) i (fun-2 (- i 1)))) (defn fun-2 [i] (if (< i 2) i (fun-1 (- i 2))))
    • tail recursion Но если мы вызовем (sum (range 10000)) то получим StackOverflowError...
    • tail recursion Правильно использовать recur: (defn sum ([[head & tail] acc] (if (nil? head) acc (recur tail (+ acc head)))) ([coll] (sum coll 0)))
    • loop/recur Альтернативой может быть loop/recur: (defn sum [coll] (loop [[head & tail] coll acc 0] (if (nil? head) acc (recur tail (+ acc head)))))
    • Destructuring
    • Ugly way for binding coll Удобно ли так писать? (let [a (nth coll 0) b (nth coll 1) c (nth coll 2)] (doSmth ...))
    • Destructuring! Что-то очень похожее на pattern matching: (let [[a b c] coll] (doSmth ...))
    • tail Мы уже видели пример ранее: (let [[a b & tail] coll] (doSmth ...))
    • maps destructuring Для maps это тоже возможно: (def my-map {"Clojure" :lang}) (let [{lang :lang} my-map] (doSmth ...))
    • Strings Destructuring доступен и для строк: (defn foo [[a & tail]] (= (clojure.string/upper-case a) (str a)))
    • :as keyword Иногда саму коллекцию тоже хочется иметь в арсенале, тогда на помощь приходит :as (defn [[head & tail :as coll]] (doSomth ...))
    • destructuring everywhere defn, fn и let - это там, где это доступно. Но из-за того, что многое приводится макросами к этим конструкциям, destructuring доступен очень много где.
    • Java compatibility
    • Calling methods Это крайне просто: (.methodName object) (.toLowerCase "AbC") ; "abc"
    • Methods with args (.methodName object args) (.equals "a" "b")
    • java.lang.Class Символ ссылающийся на имя класса также дает нам и сам класс (compare .class, classOf) (map #(.getName %) (.getMethods Boolean))
    • static things Static field: (Math/PI) Static method: (ClassName/methodName args) (Thread/activeCount) ; 1
    • Getting all together Наконец-то классический HelloWorld! (.println (System/out) "Hello, World!")
    • Operator . Есть и альтернатива всему этому… (.toUpperCase "abc") (. "abc" toUpperCase) (Thread/activeCount) (. Thread activeCount) (.equals "a" "b") (. "a" equals "b")
    • Operator .. Последовательные вызовы можно объединить: (. (. System out) println "Hello, World!") (.. System out (println "Hello, World!"))
    • operator new Есть старый добрый оператор: (new ClassName args) (new Object) (new String "text") (new java.util.HashMap)
    • dot syntax Но есть и альтернатива… (ClassName. args) (Object.) (String. "text") (java.util.HashMap.)
    • for example (let [h (java.util.HashMap.)] (.put h "a" "b") (.get h "a"))
    • import Есть и возможность импортировать имена: (import [java.util HashMap ArrayList]) (HashMap.) (ArrayList.)
    • operator doto Что делает этот оператор? (doto (HashMap.) (.put 1 "one") (.put 2 "two"))
    • instance? Аналог instanceof/isInstanceOf (instance? HashSet (HashSet.))
    • Java classes in Clojure
    • reify С помощью этого оператора можно создавать анонимные классы: (reify InterfaceName (methodName [this args] body))
    • reify А также для нескольких интерфейсов: (reify InterfaceName (methodName [this args] body) AnotherInterface (method-2 [this args] body-2))
    • Runnable (def runnable (reify Runnable (run [this] (println "text")))) (.start (Thread. runnable))
    • Array compatibility (make-array (Integer/TYPE) 4) (make-array String 3) (to-array [1 2 3]) ;untyped: java.lang.Object[] (into-array [1 2 3]) ;typed: java.lang.Long[]
    • Declaring class in Clojure
    • gen-class Класс объявить легко: (gen-class :name my.class.Name) (compile 'my.class) (my.className.)
    • :methods Объявить: :methods [[methodName [String] String]] И реализовать: (defn -methodName [arg] (str "x " arg))
    • :prefix Можно добавить префикс для понятности: :prefix prefix Тогда реализовать: (defn prefix-methodName [arg] (str "x " arg))
    • :init/:constructors Объявить имя для конструктора, и сигнатуры конструкторов: :init init :constructors [[String] [] [String String] [String]]
    • :state При создании класс можно записать некоторый state, который можно вернуть как [[super-call] state] из конструктора. Вызывать можно так: :state state (.state this)
    • :implements/:extends Указать супер класс: :extends ClassName Можно также объявить список интерфейсов: :implements [java.io.Serializable]
    • :gen-class Желательно все это использовать в макросе ns, где и указать все, что требуется: (ns my.namespace (:gen-class))
    • Polymorphism
    • Example (def circle {:type ::circle :r 10}) (def rect {:type ::rectangle :w 10 :h 20}) (defn area [{type :type :as shape}] (cond (= type ::circle) (* Math/PI (:r shape) (:r shape)) (= type ::rectangle) (* (:w shape) (:h shape))))
    • solution: multimethods ● Runtime polymorphism ● Позволяет dispatching по совершенно любому объекту
    • defmulti Объявление очень простое: (defmulti function-name "Doc string" dispatch-fn)
    • defmethod За объявлением следуют реализации: (defmethod fName1 match-1 [this] ...) (defmethod fName2 match-2 [this] ...)
    • our example (defmulti area :type) (defmethod area ::circle [circle] (* Math/PI (:r circle) (:r circle))) (defmethod area ::rectangle [rect] (* (:w rect) (:h rect)))