(clojure)



(clojure)

0 0


clojure-saratov-2015-slides


On Github niquola / clojure-saratov-2015-slides

(clojure)

Created by niquola / @niquola

Nikolay Ryzhikov

Why learn yet another lang?

Effectivnes

do more with less

Why learn functional lang?

  • simplicity
  • expressivnes
  • reuse
  • reliability
  • concurrency
var coll = [1, 2, 3, 4, 5, 6];
var acc = [];

for(var i = 0; i< coll.length && acc.length < 3; i++){
 if(i%2 == 1){
  acc.push(coll[i] + 1)
 }
}
var inc = function(x){ return x + 1; }
var odd = function(x){ return x%2 == 1; }

acc = [1, 2, 3, 4, 5, 6].map(inc).filter(odd).take(2);

Which functional lang?

  • haskell
  • ocaml/F#
  • erlang
  • scala
  • clojure

Clojure

  • Academi (AI)
  • Enterprise (JVM)
  • Hipster (Web)

How to start

with clojure?

presentation books env pet projects small projects

What is clojure?

functional LISP on JVM for concurrency by Rich Hickey

What is LISP?

John MacCarthy 1958

  • if
  • garbage collection
  • closure
  • CLOS -> smalltalk
  • hardware abstracton - C
  • math application - LISP

primitives

(= (type nil) nil)

(= (type 100) java.lang.Long)

(= (type 0.1) java.lang.Double)

(= (type "hi") java.lang.String)

(= (type #"^a.*") java.util.regex.Pattern)

(= (type :orange) clojure.lang.Keyword)

(= (type 'apple) clojure.lang.Symbol)
(= (type '(1 2 3))

 clojure.lang.PersistentList)

(= (type [1 2 3])

 clojure.lang.PersistentVector)

(= (type {:a 1 :b 2})

 clojure.lang.PersistentArrayMap)

(= (type #{1 2 3})

 clojure.lang.PersistentHashSet)

Syntax?

(ast)

function myfn(x,y)  | ["function", "myfn",
{                   |  ["x", "y"],
  return            |   ["+",
    x*x + y*y;      |    ["*", "x", "x"],
}                   |    ["*", "y", "y"]]]
                    |
myfn(3,6)           | ["myfn", "3", "6"]

(ast)

["function", "myfn",  |  [function myfn
 ["x", "y"],          |    [x y]
 ["+",                |    [+
   ["*", "x", "x"],   |      [* x x]
   ["*", "y", "y"]]]  |      [* y y]]]
                      |
["myfn", "3", "6"]    |  [myfn 3 6]

(hello clojure)

[function myfn [x y]  |  (defn myfn [x y]
  [+ [* x x]          |    (+ (* x x)
     [* y y]]]        |       (* y y)))
                      |
[myfn 3 6]            |   (myfn 3 6)

punctuation

function myfn(x,y){  | (defn myfn [x y]
 return  x*x + y*y;  |   (+ (* x x)
};                   |      (* y y)))
                     |
myfn(3,6)            | (myfn 3 6)
// 12 [{;,}]         | ;; 12 ([])

manipulate ast

(forms & s-expressions)

(special-form args)

(function-call args)

(macros-call args)

just lists

(special-forms)

(def symbol init?)
(if test then else?)
(do exprs*)
(let [bindings* ] exprs*)
(quote form)
(var symbol)
(fn name? [params* ] exprs*)
(loop [bindings* ] exprs*)
(recur exprs*)
(throw expr)
(try expr* catch-clause* finally-clause?)

(defn functions)

(defn inc [x] (+ 1 x)) ;; (def inc (fn [x] ..))
(myfn 1 2)

(defn bar
  "doc string?" ;; embed doc
  ([a b] ...)   ;; multi arity
  ([a b c] ...)

(defn constrained-fn [f x]
  {:pre  [(pos? x)]       ;; pre & post conditions
   :post [(= % (* 2 x))]} ;; contracts
  (f x))

(defn myfn [{a :a}] ;; destructuring
  ...)

(homoiconicity)

(= CODE DATA)

meta-programming

(defmacro macros)

(defmacro unless [pred f1 f2]
  (list 'if (list 'not pred) f1 f2))

(defmacro unless [pred f1 f2]
 `(if (not (~pred)) ~f1 ~f2))

(unless (> 5 (rand 10))
  "ok"
  "not ok"))

(if (not (> 5 (rand 10)))
  "ok"
  "not ok"))

(most of useful forms)

(defn myfn [args] body) ;; (def myfn (fn []..))

(cond pred1 expr1  ;; (if pred1 expr (cond ...))
      pred2 expr2)

(for [x xs] (* x x)) ;; (loop [...

(doseq [x xs] (println x)) ;; (loop [..

Functional

Programming?

чистые функции

&

функции высших порядков

чистые функции

  • теже параметры - тотже ответ
  • на других не влияет

sin(π/2) => 1

чистые функции

оперируют значениями (value)

значение

  • неизменное
  • чистая идея
  • операция порождают новое значение

чистые функции: свойства

  • на них можно расчитывать
  • легко предсказуемы
  • не злопамятны
function fullName(first, middle, last){
   return first
   + (middle[0] ? ( ' ' + middle[0]) : '')
   + ','
   + last;
}

fullName('Nicola', 'Nikolaevich', 'Ryzhikov')
//=> Nicola N. Ryzhikov

чистые функции: свойства

  • легко понимать (простота)
  • легко тестировать (надежность)
  • легко параллелить (share nothing)
  • легко переиспользовать (reuse)
  • откладывать выполнение (ленивость)

чистые функции:

идеальные компоненты

никаких скрытых зависимостей

все явно

out of the tar pit

Ну с числами и строчками понятно

А массивы, словари?

Копировать?

function myfn(somearray){
   var copy = somearray.clone()
   return copy.push('ups');
}

Персистентные

структуры данных O(1)

fixed price cpu/memory

Префиксные деревья (trie)

Array Mapped Trie

node as array && hash as index

Bitmap Trick

Persistence

structure sharing & path copying

Функции высших порядков

можно передвать функции в функции и возвращать функции из функций

Инструмент абстракции

  • передать алгоритм в алгоритм
  • сконструировать алгоритм

Работа с коллекциями

(map :name users) => ["nicola" "pavel" "marat"]

(filter odd? (range 10)) => [1 3 5 7 9]

(reduce + 0 (range 100)) => 100
(reduce * 1 (range 10)) => 10!

(->> coll
     (map inc)
     (filter odd)
     (take 5))

(take 5 (filter odd (map inc coll)))

Middleware

(defn handler [x] (/ 1 x))
(defn wrap [f]
  (fn [x]
    (if (< x 0) nil (f x))))

(def stack (wrap handler))
(stack 1) => 1
(stack 2) => 1/2
(stack 0) => null

chain of responsibility

Transducers

(reduce (fn [acc x] (+ acc x)) 0 [1 2 3 4])
(reduce (fn [acc x] (conj acc (+ x 1)) [] [1 2 3 4])

(def transducer
  (fn [f]
    (fn [acc c] (if cond (f acc c) acc))))


(def trans
 (-> (map inc) (filter odd?) (take 5)))

(trans (range 100)) => [1 3 5 7 9]

REPL driven development

nREPL server started on 54903 port
> (start sys)
> (doc map)
> (inspect sys)
> (stop sys)
> (run-tests)
> (eval ...)

vim: fireplace

Polymorphism

(into [1 2] [3 4])
;=> [ 1 2 3 4]

(into {:a 1 :b 2} {:c 4})
;=> {:a 1 :b 2 :c 3}

(protocols)

(defprotocol Speaker (say [this]))

(deftype Rubist [name]
  Speaker
  (say [this] "ruby"))

(deftype Clojurist [name]
  Speaker
  (say [this] "clojure"))

(for [x [(Rubyist "nicola") (Clojurist "nicola")]
  (say x))

(multimethods)

(defmulti encounter
  (fn [x y]
    [(:Species x) (:Species y)]))

(defmethod encounter
 [:Bunny :Lion] [b l]
 :run-away)

(defmethod encounter
 [:Bunny :Bunny] [b l]
 :sex)

Expression problem

  • add new type with fixed behavior
  • add behavior to existing type

Expression problem

(extend-protocol ICoerce

  Date
  (to-date-time [date]
    (from-date date))

  java.sql.Date
  (to-date-time [sql-date]
    (from-sql-date sql-date))

  java.sql.Timestamp
  (to-date-time [sql-time]
    (from-sql-time sql-time)))

State & Identity

  • atom (uncoord; sync)
  • ref (coord; sync)
  • agent (uncoord; async)

atom

(def state (atom {}))

(deref state) ;; or @state

(swap! state (fn [old] (assoc old :key "val")))
@state

agent

(def counter (agent 0))

@counter

(send counter inc)

;;(send counter (fn [old] (+ 1 old))

@counter ;; may be 1

refs & STM

(def account-a (ref 1000))
(def account-b (ref 1000))

;; transaction
(dosync
  (alter account-a + 100)
  (alter account-b - 100))

core.async (CSP)

core.async (CSP)

core.async

(let [c1 (upload "serious.jpg")
      c2 (upload "fun.jpg")
      c3 (upload "sassy.jpg")
      [res chan] (alts!! [c1 c2 c3 (timeout 20)])]
    (report res))

Interop

(.toUpperCase "fred")
(.getName String)
(.-x (java.awt.Point. 1 2))
(System/getProperty "java.vm.version")
Math/PI

Rich Hickey

Rich Hickey

  • Hammock Driven Development
  • Simple Made Easy
  • The Value of Values
  • The Language of the System
  • Design, Composition and Performance

best hits

Books

Resources

Thx

Q?

(clojure) Created by niquola / @niquola