clojure: lisp for the modern world (русская версия)
Post on 13-Dec-2014
3.138 Views
Preview:
DESCRIPTION
TRANSCRIPT
CLOJURELISP FOR THE MODERN WORLD
Alex Ottalexott@gmail.com, http://alexott.net/
О чем пойдет речь?
Что такое Clojure? Основы языка
Базовый синтаксис Метапрограммирование Полиморфизм Конкурентное программирование
Clojure в реальной жизни Clojure для веб-разработки
Что такое Clojure?
Функциональный (неизменяемые данные, ФВП, …)
Lisp-ообразный Конкурентное программирование Многоплатформенный (JVM, .Net, JavaScript,
etc.) Открытый исходный код и либеральная
лицензия Активное сообщество разработчиков Коммерческое применение Коммерческая поддержка
Почему ФП?
Неизменяемость данных Отсутствие побочных эффектов Функции в математическом смысле Функции – объекты первого порядка Возможность автоматической
параллелизации кода Меньше проблем с конкурентным
выполнением кода
Почему Lisp?
Простой синтаксис - code as data structures (Homoiconic)
Метапрограммирование (макросы) Создание доменно-специфических языков Генерация кода во время компиляции Возможность избежать повторений
Генерация и выполнение кода в runtime
Интерактивная разработка Динамически типизированный
Отличия от других Lisp’ов
Немного упрощенный синтаксис -- меньше скобочек
Неизменяемые данные Добавлено больше базовых структур
данных: вектора, отображения (maps) и т.п. Расширяемый reader, но без reader macros "Ленивые" коллекции Мета-информация привязанная к данным и
функциям Case-sensitive names Исключения вместо условий/рестартов
Базовый синтаксис
Код – структуры данных Выражение – список, первый элемент
бывает: Функция Макрос Специальная форма
Примеры:(def a 1)
(+ 1 2)
(defn func [x] (* x x))
(defmacro when [x & body]
`(if ~x (do ~@body)))
Как выполняется код
Базовые типы данных
Числа (целые, рациональные, вещественные): 42, 1/3, 1N, 4.2, 42.2M
Строки: "String» Знаки (characters): \a, \newline, … Регулярные выражения: #"\d+" Логические значения: true, false nil – как null в Java Символ (symbol): name Keyword: :name, (:name {:name "test"})
Коллекции
Разные коллекции: Списки: (1 2 3 "abc") Вектора: [1 2 3] Отображения (maps): {:k1 1234 :k2 "value"}
Множества: #{:val1 "text" 1 2 10} Persistent & transient коллекции Вектора, отображения и множества сами
являются функциями:([1 2 3] 2) => 3({:a 1 :b 2 :c 3} :b) => 2
Persistent collections
Новая копия данных при изменении
Затрагивается только измененная часть
Производительность сравнима с коллекциями Java
Последовательности
Последовательности (sequences): Коллекции Clojure & Java, массивы,
iterable, … "Ленивые" операции над
последовательностями Могут быть бесконечными Один набор операций над
последовательностями: map, reduce, filter, …
Управляющие структуры
Определение переменной: (def name value) Определение функции: (defn name [args…] body), (fn [args…] body), #(body)
Локальные переменные: (let [name1 value1 name2 value2] body)
Ветвление: if, cond, when, … Последовательное выполнение: do Цикл: loop/recur List comprehension: for Исключения: try/catch, throw
Метапрограммирование и макросы
Макросы – функции, выполняемые во время компиляции
Макросы получают код и возвращают новый код
Генерация кода: Стандартные функции работы со
списками Quasi-quote (`) и операторы подстановки: ~ и ~@
Суффикс # для генерации уникальных имен
macroexpand-1 & macroexpand для отладки
Большая часть библиотеки Clojure – макросы
Макросы: примеры
Макрос (любой из двух):(defmacro when [test & body]
(list 'if test (cons 'do body))) (defmacro when [x & body]
`(if ~x (do ~@body)))
Использование:(when (pos? a)
(println "positive") (/ b a))
Раскрывается в:(if (pos? a)
(do (println "positive") (/ b a)))
Полиморфизм: мультиметоды CLOS-подобный полиморфизм Диспатчеризация в зависимости от
любого условия и количества аргументов
Диспатчеризация выполняется функцией
Диспатчеризация во время выполнения
Возможность построения иерархических зависимостей между типами
Мультиметоды: примеры
Определение:(defmulti m-example class)
(defmethod m-example String [this]
(println "This is string '" this "'"))
(defmethod m-example java.util.Collection [this]
(print "This is collection!"))
Использование:(m-example "Hello") => "This is string 'Hello'"
(m-example [1 2 3]) => "This is collection!"
(m-example '(1 2 3)) => "This is collection!”
Мультиметоды: примеры
(defmulti encounter
(fn [x y] [(:Species x) (:Species y)]))
(defmethod encounter [:Bunny :Lion] [b l] :run-away)
(defmethod encounter [:Lion :Bunny] [l b] :eat)
(defmethod encounter [:Lion :Lion] [l1 l2] :fight)
(defmethod encounter [:Bunny :Bunny] [b1 b2] :mate)
(def b1 {:Species :Bunny})
(def b2 {:Species :Bunny})
(def l1 {:Species :Lion})
(def l2 {:Species :Lion})
(encounter b1 b2) ==> :mate
(encounter b1 l1) ==> :run-away
(encounter l1 b1) ==> :eat
(encounter l1 l2) ==> :fight
Полиморфизм: протоколы
Способ решения expression problem Диспатчеризация только по типу данных Быстрее чем мультиметоды defprotocol: определяет протокол deftype: новые типы данных
(низкоуровневый) defrecord: новые типы данных (только
данные) Можно реализовать протокол для
произвольных классов или интерфейсов (extend-protocol & extend-type)
Протоколы: примеры
(defprotocol Hello "Test of protocol"
(hello [this] "hello function"))
(defrecord B [name] Hello
(hello [this] (str "Hello " (:name this) "!")))
(hello (B. "User")) => "Hello User!"
(extend-protocol Hello String
(hello [this] (str "Hello " this "!")))
(hello "world") => "Hello world!"
(extend-protocol Hello java.lang.Object
(hello [this] (str "Hello '" this "'! ("
(type this) ")")))
(hello 1) => "Hello '1'! (class java.lang.Integer)”
Concurrency: пространство и время
Clojure разделяет концепции состояния (state) и имени (identity)
Состояние (значение) не изменяется! Identity просто указывает на новое состояние
Конкурентное программирование
Средства для изменяемых данных: Ссылки (refs): синхронное,
координированное изменение (STM) Агенты: асинхронное,
некоординированное изменение Атомы: синхронное,
некоординированное изменение Vars: thread-local изменение
@ или deref для доступа к данным Валидаторы и функции-наблюдатели
Конкурентное программирование
Параллельное выполнение кода: future pmap, pvalues, pcalls потоки JVM
Синхронизация: promise Отложенное выполнение кода: delay Конкурентные примитивы из JVM
Сoncurrency: примеры
(defn acc-validator [new]
(if (neg? (:amount new))
(throw (Exception. "Not money on account!"))
true))
(defn make-account [name init-amount]
(let [r (ref {:name name :amount init-amount})]
(set-validator! r acc-validator) r))
(def acc1 (make-account "User1" 1000))
(def acc2 (make-account "User2" 300))
(defn money-transfer [from to amount]
(dosync (alter from update-in [:amount] - amount)
(alter to update-in [:amount] + amount)))
(money-transfer acc1 acc2 100) => acc1 = 900, acc2 = 400
(money-transfer acc1 acc2 1000) => Exception “No money”
Взаимодействие с платформой Взаимодействие с платформой:
Создание объектов: (Class.) или (new Class)
Вызов методов или доступ к членам классов:
`.’, `..’ или doto Генерация классов и интерфейсов
Вызов Clojure кода из Java, и т.п. Примитивы для работы с массивами Генерация и перехват исключений
Interoperability: примеры
Создание объектов:(new java.util.Date) <==> (java.util.Date.)
Вызов методов:(.substring "Hello World" 0 5) => "Hello"
(. "Hello World" substring 0 5) => "Hello"
Math/PI => 3.141592653589793
(Integer/parseInt "42") => 42
Clj: (.. System getProperties (get "os.name"))Java: System.getProperties().get("os.name")(doto (java.util.HashMap.)
(.put "a" 1) (.put "b" 2))
IDE & средства сборки кода
Поддержка в IDE/редакторах: Eclipse (Counterclocwise) Netbeans (Enclojure) IntelliJ IDEA (La Clojure) Emacs + SLIME или nRepl VimClojure Textmate, Sublime Text 2, Jedit
Средства сборки кода: Поддержка Clojure в Maven, Ant, Cake, Gradle Leiningen: самый популярный
Библиотеки и репозитории
Простой доступ к библиотекам JVM Библиотеки написанные на Clojure:
Web-разработка: Compojure, Ring, Scriptjure, Noir
RDBMS: ClojureQL, clojure.java.jdbc, Korma NoSQL: Monger, Clouch, … Contrib библиотеки: core.* GUI: Seesaw Логическое программирование: core.logic
Репозитории: Maven Central, Clojars.org
Как все это дело изучать?
Много книг Интерактивные сайты: 4clojure.com,
tryclj.com, himera.herokuapp.com, … Множество видео-лекций Списки рассылки: clojure, clojure-
russian, … Группы пользователей Конференции в США и Европе IRC Clojure/core: поддержка, тренинги, …
Webdev: server side
Ring – низкоуровневая основа: Функции-обработчики Объекты request/response Middleware – функции-обертки для
обработчика Более высокоуровневые фреймворки:
Compojure – упрощение разработки с Ring Noir – микрофреймворк на базе Ring
Hiccup – генерация HTML Плугины для Leiningen: lein-ring, lein-noir, … Standalone или war
Webdev: server side, примеры
(defroutes app-routes
(GET ["/user/:id", :id #"[0-9]+"] [id]
(get-user-info id))
(GET "/users/" []
(get-user-list))
(GET "/" [] "It works!\n")
(route/resources "/")
(route/not-found "Resource isn't found"))
(def app (-> #'app-routes
wrap-base-url
handler/site
(wrap-reload '[ws])))
Webdev: ClojureScript
Подмножество Clojure: Пространства имен Неизменяемые данные ….
Библиотеки из Clojure & JavaScript Производительный Оптимизуется с помощью Google Closure Может выполняться на Node.js Отличия от Clojure:
нет ссылок/транзакций, агентов и vars – только атомы отличия в объявлении пространств имен нет компиляции и вычисления кода в run-time нет Java-специфичных вещей, как gen-class, gen-
interface, …
Webdev: deployment
Поддержка развертывания для: Google App Engine Heroku RedHat's OpenShift Elastic Beanstalk
Платформо-специфичные библиотеки Плагины для Leiningen
Вопросы
Спасибо за внимание
top related