Why learn yet another lang?
do more with less
Why learn functional lang?
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?
What is LISP?
(= (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?
function myfn(x,y) | ["function", "myfn",
{ | ["x", "y"],
return | ["+",
x*x + y*y; | ["*", "x", "x"],
} | ["*", "y", "y"]]]
|
myfn(3,6) | ["myfn", "3", "6"]
["function", "myfn", | [function myfn
["x", "y"], | [x y]
["+", | [+
["*", "x", "x"], | [* x x]
["*", "y", "y"]]] | [* y y]]]
|
["myfn", "3", "6"] | [myfn 3 6]
[function myfn [x y] | (defn myfn [x y]
[+ [* x x] | (+ (* x x)
[* y y]]] | (* y y)))
|
[myfn 3 6] | (myfn 3 6)
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 ([])
(special-form args) (function-call args) (macros-call args)
just lists
(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 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
...)
(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"))
(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 [..
&
оперируют значениями (value)
function fullName(first, middle, last){
return first
+ (middle[0] ? ( ' ' + middle[0]) : '')
+ ','
+ last;
}
fullName('Nicola', 'Nikolaevich', 'Ryzhikov')
//=> Nicola N. Ryzhikov
никаких скрытых зависимостей
все явно
function myfn(somearray){
var copy = somearray.clone()
return copy.push('ups');
}
Персистентные
структуры данных O(1)
fixed price cpu/memory
можно передвать функции в функции и возвращать функции из функций
(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)))
(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
(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]
nREPL server started on 54903 port > (start sys) > (doc map) > (inspect sys) > (stop sys) > (run-tests) > (eval ...)
vim: fireplace
(into [1 2] [3 4])
;=> [ 1 2 3 4]
(into {:a 1 :b 2} {:c 4})
;=> {:a 1 :b 2 :c 3}
(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))
(defmulti encounter
(fn [x y]
[(:Species x) (:Species y)]))
(defmethod encounter
[:Bunny :Lion] [b l]
:run-away)
(defmethod encounter
[:Bunny :Bunny] [b l]
:sex)
(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
(def state (atom {}))
(deref state) ;; or @state
(swap! state (fn [old] (assoc old :key "val")))
@state
(def counter (agent 0)) @counter (send counter inc) ;;(send counter (fn [old] (+ 1 old)) @counter ;; may be 1
(def account-a (ref 1000)) (def account-b (ref 1000)) ;; transaction (dosync (alter account-a + 100) (alter account-b - 100))
(let [c1 (upload "serious.jpg")
c2 (upload "fun.jpg")
c3 (upload "sassy.jpg")
[res chan] (alts!! [c1 c2 c3 (timeout 20)])]
(report res))
(.toUpperCase "fred") (.getName String) (.-x (java.awt.Point. 1 2)) (System/getProperty "java.vm.version") Math/PI