Skip to content

Instantly share code, notes, and snippets.

@dark4eg
Forked from dbushenko/gist:5220377
Created March 22, 2013 22:37
Show Gist options
  • Save dark4eg/5225300 to your computer and use it in GitHub Desktop.
Save dark4eg/5225300 to your computer and use it in GitHub Desktop.
(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