-
-
Save dark4eg/5225300 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns lection02.core) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Namespaces | |
;; Refer | |
;;--------------- | |
(comment | |
(refer 'clojure.string :only '[capitalize trim]) | |
(capitalize (trim " hOnduRAS ")) | |
;; Require | |
;;--------------- | |
(require 'clojure.string) | |
(require '(clojure.java io)) | |
(clojure.java.io/file "filename") | |
(require '[clojure.java.io :as io]) | |
(io/file "Filename") | |
;; :refer takes a list of symbols to refer from the namespace or the :all | |
;; keyword to bring in all public vars. | |
(require '(clojure.java.io :refer :all)) | |
;; :reload forces loading of all the identified libs even if they are | |
;; already loaded | |
;; :reload-all implies :reload and also forces loading of all libs that the | |
;; identified libs directly or indirectly load via require or use | |
(require '[clojure.string :as str :only [replace]] :reload-all) | |
;; Use | |
;;--------------- | |
(use 'clojure.repl) | |
;; Import | |
;;--------------- | |
(import 'java.util.Date) | |
(import '(java.util Date Timer Random)) | |
;; Namespace | |
;;--------------- | |
(ns foo.bar | |
(:refer-clojure :exclude [ancestors printf]) | |
(:require (clojure.contrib sql combinatorics)) | |
(:use (my.lib this that)) | |
(:import (java.util Date Timer Random) | |
(java.sql Connection Statement))) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Java Integration | |
;; Type hints | |
(defn my-prn [^String s] (println s)) | |
;; gen-class | |
;; project.clj | |
(ns task01.core | |
(:require [pl.danieljanus.tagsoup :refer :all]) | |
(:gen-class)) | |
(defn -main [] | |
(println "Hello, World!")) | |
(ns com.example) | |
(gen-class | |
:name com.example.Demo | |
:implements [org.my.SomeInterface] | |
:extends [org.my.SomeSuperclass] | |
:state state | |
:init init ;; Called before constructors, initializes state | |
:prefix "-" | |
:main false | |
;; declare only new methods, not superclass methods | |
:methods [[setLocation [String] void] ;; specify only parameter types | |
[getLocation [] String]]) | |
;; when we are created we can set defaults if we want. | |
(defn -init [] | |
"store our fields as a hash" | |
[[] (atom {:location "default"})]) | |
(defn setfield [this key value] | |
(swap! (.state this) into {key value})) | |
(defn getfield | |
[this key] | |
(@(.state this) key)) | |
(defn -setLocation [this loc] | |
(setfield this :location loc)) | |
(defn -getLocation | |
[this] | |
(getfield this :location)) | |
;; Clojure from java | |
;; class RT { | |
;; ... | |
;; public static void load(String name); | |
;; public static void loadResourceScript(String filename); | |
;; public static void maybeLoadResourceScript(String filename); | |
;; public static Object readString(String code); | |
;; public static Var var(String ns, String name); | |
;; public static Var var(String ns, String name, Object value); | |
;; ... | |
;; } | |
;; class Compiler { | |
;; ... | |
;; public static Object eval(Object obj); | |
;; ... | |
;; } | |
;; class Var { | |
;; ... | |
;; public Object get(); | |
;; public Object invoke(Object args...); | |
;; ... | |
;; } | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; REPL | |
(in-ns 'lection02.core) | |
;; C-c C-d | |
(doc filter) | |
;; C-c C-s | |
(source filter) | |
(apropos "map") | |
;; C-x C-e | |
;; C-x C-k | |
;; Start nrepl server | |
;; ------------------- | |
(use '[clojure.tools.nrepl.server :only (start-server stop-server)]) | |
(defonce server (start-server :port 7888)) | |
;; Connect to nrepl server | |
;; ------------------------ | |
(require '[clojure.tools.nrepl :as repl]) | |
(with-open [conn (repl/connect :port 7888)] | |
(-> (repl/client conn 1000) | |
(repl/message {:op :eval :code "(+ 1 1)"}) | |
repl/response-values)) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Про замыкания | |
;; | |
(defn my-cons [a b] | |
(fn [get-first?] | |
(if get-first? | |
a | |
b))) | |
(defn my-car [cell] | |
(cell true)) | |
(defn my-cdr [cell] | |
(cell false)) | |
(def my-cell (my-cons :first-elem :second-elem)) | |
(my-car my-cell) | |
(my-cdr my-cell) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Подробнее о коллекциях | |
;; В первую очередь они используются в терминах абстракций, а не особенностей конкретной реализации. | |
;; Эти структуры данных являются неизменяемыми и постоянными, что очень важно с точки зрения эффективности функционального программирования на языке Clojure. | |
;; Имеется семь основных абстракций, поддерживаемых реализациями структур данных в Clojure: | |
;; - коллекция; | |
;; - последовательность; | |
;; - ассоциативная коллекция; | |
;; - индексируемая коллекция; | |
;; - стек; | |
;; - множество; | |
;; - сортированная коллекция. | |
;; Коллекции (collections) | |
;; conj – добавляет элемент в коллекцию; | |
;; seq – возвращает коллекцию в виде последовательности; | |
;; count – возвращает количество элементов в коллекции; | |
;; empty – возвращает пустой экземпляр, тип которого соответствует исходной коллекции; | |
;; = – определяет равенство коллекций | |
;; Последовательности | |
;; seq преобразует свой аргумент в последовательность; | |
;; first, rest и next позволяют извлекать элементы из последовательностей; | |
;; lazy-seq производит «ленивую» последовательность (lazy sequence), элементы которой являются результатом вычисления выражения. | |
;; В последовательность можно преобразовать: | |
;; все типы коллекций в языке Clojure; | |
;; все коллекции в Java (то есть, java.util.*); | |
;; все ассоциативные массивы в Java; | |
;; все реализации интерфейса java.lang.CharSequence, включая String; | |
;; любые типы, реализующие интерфейс java.lang.Iterable | |
;; массивы; | |
;; nil (то есть, null, возвращаемый Java-методами); | |
;; любые типы, реализующие интерфейс clojure.lang.Seqable. | |
(seq "Clojure") | |
(seq {:a 1, :c 3, :b 2}) | |
(seq (java.util.ArrayList. [1 2 3])) | |
;; Последовательности -- не списки | |
;; определение длины последовательности является дорогостоящей операцией; | |
;; значения, содержащиеся в последовательностях, могут вычисляться только при непосредственном обращении к ним; | |
;; вычисления, производящие значения для «ленивой» последовательности (lazy sequence), могут представлять собой неограниченную прогрессию, производя тем самым бесконечные последовательности, длину которых определить невозможно. | |
;; lazy-seq | |
(range 1 10) | |
(range 20) | |
;; Takes a body of expressions that returns an ISeq or nil, and yields | |
;; a Seqable object that will invoke the body only the first time seq | |
;; is called, and will cache the result and return it on all subsequent | |
;; seq calls. | |
(defn random-ints | |
[limit] | |
(lazy-seq | |
(cons (rand-int limit) | |
(random-ints limit)))) | |
(take 10 (random-ints 50)) | |
;; Код, определяющий «ленивую» последовательность, должен минимизировать побочные эффекты. | |
;; В Clojure отложенные вычисления возможны только с последовательностями, а остальные структуры данных вычисляются немедленно. «Ленивые» последовательности в Clojure позволяют прозрачно обрабатывать большие объемы данных, не умещающиеся в памяти, и выражать алгоритмы в более однородном, декларативном и конвейерном виде; в этом контексте последовательности можно рассматривать как своеобразный способ организации вычислений, а не как коллекции. | |
(defn fib [a b] (cons a (lazy-seq (fib b (+ b a))))) | |
(take 10 (fib 1 1)) | |
;; В общем случае последовательность может быть создана на основе коллекции либо явно – вызовом функции seq, либо неявно – вызовом другой функции (такой как map), применяющей функцию seq к своим аргументам. Однако сужествует еще два способа создания последовательностей: cons и list | |
;; Oбратите внимание, что функция cons в Clojure имеет мало общего с функцией cons в других диалектах. Аналогично списки в языке Clojure не являются последовательностями cons-ячеек | |
;; Функция cons принимает два аргумента – значение, служащее головой новой последовательности, и другую коллекцию, последовательное представление которой будет служить хвостом: | |
(cons 0 (range 1 5)) | |
;; Для простоты можно считать, что cons всегда добавляет голову в начало коллекции, представляющей хвост, независимо от ее конкретного типа. Этим она отличается от функции conj: | |
(cons :a [:b :c :d]) | |
;; Еще примеры | |
;; repeat | |
(take 5 (repeat "x")) | |
;; replicate | |
(replicate 7 1) | |
;; cycle | |
(take 5 (cycle ["a" "b"])) | |
;; iterate | |
;; Returns a lazy sequence of x, (f x), (f (f x)) etc. f must be free of side-effects | |
(take 5 (iterate inc 3)) | |
;; line-seq | |
;; Returns the lines of text from rdr as a lazy sequence of strings. | |
;; rdr must implement java.io.BufferedReader. | |
(line-seq rdr) | |
;; tree-seq | |
;; Returns a lazy sequence of the nodes in a tree, via a depth-first walk. | |
(tree-seq seq? identity '((1 2 (3)) (4))) | |
;; xml-seq | |
;; A tree seq on the xml elements as per xml/parse | |
(use '[clojure.data.xml :only [parse-str]]) | |
(xml-seq (parse-str xml-text)) | |
;; file-seq | |
;; A tree seq on java.io.Files | |
(def f (clojure.java.io/file "D:\\Games")) | |
;; doall | |
;; dorun | |
;; maps | |
;; assoc – устанавливает новые взаимосвязи между ключами и значениями в указанной коллекции; | |
;; dissoc – удаляет взаимосвязи с указанными ключами из коллекции; | |
;; get – отыскивает значение, соответствующее указанному ключу в коллекции; | |
;; contains? – предикат, возвращающий true, только если коллекция содержит значение, связанное с указанным ключом. | |
(assoc {:a 1, :b 2} | |
:x 4 | |
:y 5 | |
:z 6) | |
(dissoc {:a 1, :b 2, :c 3} :a :c) | |
;; Вектор тоже является ассоц. массивом, только ключ у вектора - его индекс | |
(assoc [1 2 3] 0 7) | |
;; Программисты на Clojure часто допускают ошибку, полагая, что contains? отыскивает в коллекции именно значение, то есть, считают, что эту функцию можно использовать для поиска определенного числового значения, в векторе, таком как [0 1 2 3]. Это заблуждение может приводить к весьма странным, на первый взгляд, результатам: | |
(contains? [1 2 3] 3) | |
(contains? [1 2 3] 2) | |
;; Внимание! nil возвращается, если значение не найдено, но это также может быть валидным значением элемента коллекции. | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Про хитрые функции | |
;; | |
;;;;;;;;;;;;;;;;; | |
;; trampoline | |
(defn trampoline | |
([f] | |
(let [ret (f)] | |
(if (fn? ret) | |
(recur ret) | |
ret))) | |
([f & args] | |
(trampoline #(apply f args)))) | |
(defn foo [x] | |
(if (< x 0) | |
(println "done") | |
#(foo (do (println :x x) (dec x))))) | |
;; Внимание, здесь я ошибся! Следующий код все равно потребляет стек. | |
;; | |
;; (def my-tree [1 [2 3 [4 5]] [6 7] 8 9]) | |
;; (defn my-walker1 [func tree] | |
;; (func tree) | |
;; (if (coll? tree) | |
;; (dorun (map #(my-walker1 func %) tree)))) | |
;; (my-walker1 println my-tree) | |
;; (defn my-walker2 [func tree] | |
;; (func tree) | |
;; (if (coll? tree) | |
;; (doall (map #(fn [f t] (my-walker2 func %)) tree)))) | |
;; (trampoline my-walker2 println my-tree) | |
;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; comp | |
;; comp возвращает новую функцию! | |
(defn comp | |
([] identity) | |
([f] f) | |
([f g] | |
(fn | |
([] (f (g))) | |
([x] (f (g x))) | |
([x y] (f (g x y))) | |
([x y z] (f (g x y z))) | |
([x y z & args] (f (apply g x y z args))))) | |
([f g h] | |
(fn | |
([] (f (g (h)))) | |
([x] (f (g (h x)))) | |
([x y] (f (g (h x y)))) | |
([x y z] (f (g (h x y z)))) | |
([x y z & args] (f (g (apply h x y z args)))))) | |
([f1 f2 f3 & fs] | |
(let [fs (reverse (list* f1 f2 f3 fs))] | |
(fn [& args] | |
(loop [ret (apply (first fs) args) fs (next fs)] | |
(if fs | |
(recur ((first fs) ret) (next fs)) | |
ret)))))) | |
(def my-comp (comp seq str +)) | |
(my-comp 11 12 13) | |
(filter (comp not zero?) [0 1 0 2 0 3 0 4]) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; threads -> ->> | |
(-> "a b c d" | |
.toUpperCase | |
(.replace "A" "X") | |
(.split " ") | |
first) | |
(def person | |
{:name "Mark Volkmann" | |
:address {:street "644 Glen Summit" | |
:city "St. Charles" | |
:state "Missouri" | |
:zip 63304} | |
:employer {:name "Object Computing, Inc." | |
:address {:street "12140 Woodcrest Dr." | |
:city "Creve Coeur" | |
:state "Missouri" | |
:zip 63141}}}) | |
(((person :employer) :address) :city) | |
(-> person | |
:employer | |
:address | |
:city) | |
(reduce + | |
(take 10 | |
(filter even? | |
(map #(* % %) | |
(range))))) | |
(->> (range) | |
(map #(* % %)) | |
(filter even?) | |
(take 10) | |
(reduce +)) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; apply | |
(apply + [1 2 3]) | |
(apply str ["abc" "def" "gh"]) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; partial | |
(defn partial | |
([f arg1] | |
(fn [& args] (apply f arg1 args))) | |
([f arg1 arg2] | |
(fn [& args] (apply f arg1 arg2 args))) | |
([f arg1 arg2 arg3] | |
(fn [& args] (apply f arg1 arg2 arg3 args))) | |
([f arg1 arg2 arg3 & more] | |
(fn [& args] (apply f arg1 arg2 arg3 (concat more args))))) | |
(def my-plus (partial + 2)) | |
(my-plus 5 10) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; iterate | |
(take 10 (iterate inc 5)) | |
(take 10 (iterate (partial + 2) 0)) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; memoize | |
(defn my-func [a] | |
(println "doing some work") | |
(+ a 10)) | |
(take 10 (iterate my-func 0)) | |
(def myfunc-memo (memoize my-func)) | |
(take 10 (iterate myfunc-memo 0)) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Деструктуризация | |
(defn my-destr1 [a b & args] | |
(println a) | |
(println b) | |
(println args)) | |
(my-destr1 1 2 3 4) | |
(defn my-destr2 [a b & args] | |
(let [c (first args) | |
d (second args)] | |
(+ a b c d))) | |
(my-destr2 1 2 3 4) | |
(defn my-destr3 [a b & [c d]] | |
(+ a b c d)) | |
(my-destr3 1 2 3 4) | |
(defn my-destr4 [a b & [c d & args]] | |
(if-not (empty? args) (println args)) | |
(+ a b c d)) | |
(my-destr4 1 2 3 4 5 6 7 8) | |
(def data {:a 1, :b 2, :c 3}) | |
(defn my-destr5 [dat] | |
(let [a (:a dat) | |
b (:b dat) | |
c (:c dat)] | |
(println a b c))) | |
(my-destr5 data) | |
(defn my-destr6 [{my-a :a, my-b :b, my-c :c}] | |
(println my-a my-b my-c)) | |
(my-destr6 data) | |
(defn my-destr7 [{:keys [a b c]}] | |
(println a b c)) | |
(my-destr7 data) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Philosophy | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Delay | |
;; Конструкция delay откладывает выполнение некоторого блока кода до момента его разыменования | |
(def d (delay (println "Running...") | |
:done!)) | |
(deref d) | |
@d | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; Future | |
;; Программный код в определении future выполняется в другом потоке | |
(def long-calculation (future (apply + (range 1e8)))) | |
@long-calculation | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; pmap | |
(pmap inc [1 2 3 4 5]) | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; atom | |
;; нескоординированный, синхронный | |
(def my-atom (atom {:name "Ivan", :age 20})) | |
@my-atom | |
(reset! my-atom {:name "Sergei", :age 30}) | |
(def xs (atom #{1 2 3})) | |
(do (future (swap! xs (fn [v] | |
(Thread/sleep 250) | |
(println "trying 4") | |
(conj v 4)))) | |
(future (swap! xs (fn [v] | |
(Thread/sleep 500) | |
(println "trying 5") | |
(conj v 5))))) | |
@xs | |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
;; ref | |
(def foo (ref {})) | |
(dosync | |
(ref-set foo {:foo "bar"})) | |
(def names (ref [])) | |
(dosync | |
(alter names conj "Ivanov")) | |
(dosync | |
(alter names conj "Petrov")) | |
(def ivanov-account (ref 100)) | |
(def petrov-account (ref 100)) | |
(defn transfer-money [from to amount] | |
(dosync | |
(alter from - amount) | |
(alter to + amount))) | |
(transfer-money ivanov-account petrov-account 20) | |
) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment