Введение в Clojure (Margincon 2010) (original) (raw)
1. Язык Clojure Небольшое введение Alex Ott http://alexott.net MarginCon 2010 Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 1 / 34
2. О чем пойдет речь? 1 Что такое Clojure? 2 Основы языка 3 Взаимодействие с Java 4 Конкурентное программирование 5 Clojure в реальной жизни 6 Источники информации Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 2 / 34
3. Что такое Clojure? Lisp’ообразный язык, созданный Rich Hickey. Анонсирован в 2007-м году. Спроектирован для работы на существующих платформах – JVM и .Net (в разработке) Функциональный язык с неизменяемыми, по умолчанию, данными Упор на поддержку конкурентного выполнения кода Открытый исходный код и либеральная лицензия Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 3 / 34
4. Причины создания нового языка Lisp, но не отягощенный совместимостью с предыдущими версиями/диалектами Неизменяемость данных и больший упор на ФП Поддержка конкурентного программирования на уровне языка Лучшая интеграция с целевыми платформами по сравнению с прямым переносом существующих языков Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 4 / 34
5. Основные возможности Динамически-типизированный язык Простой синтаксис, как у всех Lisp’ов Поддержка интерактивной разработки Спроектирован в терминах абстракций Метапрограммирование Мультиметоды и протоколы (версия 1.2) Компилируется в байт-код целевых платформ Доступ к большому количеству существующих библиотек Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 5 / 34
6. Отличия от других Лиспов Измененный синтаксис, с меньшим кол-вом скобок Изменения в наименовании Больше first-class структур данных – отображения (map), наборы (set), вектора Неизменяемые, по умолчанию, данные Связывание мета-данных с переменными и функциями Ленивые коллекции Нет поддержки макросов для процедуры чтения Регистро-зависимые имена Отсутствие tail call optimization (ограничение JVM) – явные циклы loop/recur Исключения вместо сигналов и рестартов Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 6 / 34
7. Базовые типы данных Целые числа произвольного размера – 14235344564564564564 Рациональные числа – 26/7 Вещественные числа – 1.2345 и BigDecimals – 1.2345M Строки (String из Java) – "hello world" Буквы (Character в Java) – a, b, . . . Регулярные выражения – #"[abc]*" Boolean – true и false nil – также как null в Java, не является пустым списком как в Lisp Символы (symbol) – test, var1, . . . Ключевые символы (keywords) – :test, :hello, . . . Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 7 / 34
8. Структуры данных Отдельный синтаксис для разных коллекций: Списки – (1 2 3 "abc") Вектора – [1 2 3 "abc"] Отображения (maps) – {:key1 1234 :key2 "value"} Наборы (sets) – #{:val1 "text" 1 2 10} Последовательность – абстракция для работы со всеми коллекциями (в том числе и классов Java/.Net) Общая библиотека функций для работы с последовательностями Ленивые операции над последовательностями Вектора, отображения, наборы сами являются функциями – упрощение доступа к данным Стабильные (persistent) коллекции “Переходные” (transients) коллекции – оптимизация производительности defstruct – оптимизация отображений для объявления сложных структур Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 8 / 34
9. Синтаксис языка Простой синтаксис – программа как структуры данных Процедура чтения (reader) преобразует программу в структуры данных Все объекты представляют сами себя за исключением символов и списков Символы связывают значение с “переменной” Списки рассматриваются как формы, которые могут быть: Специальной формой – def, let, if, loop, . . . Макросом Функцией, или выражением, которое приводится к функции (maps, keywords, . . . ) Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 9 / 34
10. Пример кода ( defn f i b o ( [ ] ( concat [1 1] ( f i b o 1 1))) ([ a b] ( l e t [ n (+ a b ) ] ( l a z y −s e q ( c o n s n ( f i b o b n ) ) ) ) ) ) ( t a k e 100000000 ( f i b o ) ) ( defn vrange2 [ n ] ( loop [ i 0 v ( transient [])] ( i f (< i n ) ( recur ( inc i ) ( conj ! v i )) ( persistent ! v )))) Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 10 / 34
11. Функции Функции как first-class objects Возможность разного кол-ва аргументов в функциях Определение функций: defn – top-level функции, fn – анонимные функции Упрощенный синтаксис для анонимных функций – #(code). Например: (map #(.toUpperCase %) ["test" "hello"]) (map #(vector %1 %2) [1 2 3] [4 5 6]) Возможность задания тестов и pre/post-условий в метаданных. Например, ( d e f n c o n s t r a i n e d −s q r [ x ] { : p r e [ ( pos ? x ) ] : p o s t [( > % 1 6 ) , (< % 2 2 5 ) ] } (∗ x x ) ) Функция компилируется в отдельный класс Java Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 11 / 34
12. Метапрограммирование и макросы Макрос получает на вход код и возвращает новый код, который будет откомпилирован Очень большая часть языка написана с помощью макросов Также как и функции, могут иметь переменной число аргументов Код можно генерировать с помощью функций для работы со списками, но удобней пользоваться quasi-quote – ‘ и операторами подстановки – , и ~@ Суффикс # в именах используется для генерации уникальных имен macroexpand-1 & macroexpand – средства отладки Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 12 / 34
13. Примеры макросов Стандартный макрос when: ( d e f m a c r o when [ t e s t & body ] ( l i s t ’ i f t e s t ( c o n s ’ do body ) ) ) при следующем использовании ( when ( pos ? a ) ( p r i n t l n " p o s i t i v e ") (/ b a ) ) раскроется в: ( i f ( pos ? a ) ( do ( p r i n t l n " p o s i t i v e ") (/ b a ) ) ) Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 13 / 34
14. Примеры макросов Стандартный макрос and ( d e f m a c r o and ( [ ] true ) ([ x] x) ( [ x & next ] ‘ ( l e t [ and# ~x ] ( i f and# ( and ~@next ) and # ) ) ) ) раскрывается в разные формы, в зависимости от числа аргументов: user> ( macroexpand ’ ( and ) ) == t r u e > user> ( macroexpand ’ ( and (= 1 2 ) ) ) == (= 1 2 ) > user> ( macroexpand ’ ( and (= 1 2 ) (= 3 3 ) ) ) ==> ( let∗ [ and__4457__auto__ (= 1 2)] ( if and__4457__auto__ ( c l o j u r e . c o r e / and (= 3 3)) and__4457__auto__ ) ) Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 14 / 34
15. Полиморфизм и мультиметоды Расширяемость Мультиметоды не привязаны к типам/классам Диспатчеризация на основании нескольких параметров Решение принимается на основании результата функции диспатчеризации Отличается от CLOS – отсутствие :before, :after, . . . defmulti – аналог defgeneric. Определяется как ( defmulti func−name dispatch−fn) + набор определений конкретных методов (через defmethod) Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 15 / 34
16. Пример мультиметодов Простой пример диспатчеризации по классу: −e ( d e f m u l t i m xample c l a s s ) −e ( d e f m e t h od m x a m p l e S t r i n g [ t h i s ] ( p r i n t l n " This i s s t r i n g ’" t h i s " ’")) −e ( d e f m e t h od m x a m p l e j a v a . u t i l . C o l l e c t i o n [ t h i s ] ( p r i n t " This i s c o l l e c t i o n ! " ) ) и получим при запуске: −e (m x a m p l e " H e l l o " ) == " T h i s i s s t r i n g ’ H e l l o ’ " > −e (m x a m p l e [ 1 2 3 ] ) == " T h i s i s c o l l e c t i o n ! " > −e (m x a m p l e ’ ( 1 2 3 ) ) == " T h i s i s c o l l e c t i o n ! " > Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 16 / 34
17. Более сложный пример диспатчеризации ( defmulti encounter ( fn [ x y ] [ ( : Species x ) ( : Species y ) ] ) ) ( d e f m e t h od e n c o u n t e r [ : Bunny : L i o n ] [ b l ] : run−away ) ( d e f m e t h od e n c o u n t e r [ : L i o n : Bunny ] [ l b ] : e a t ) ( d e f m e t h od e n c o u n t e r [ : L i o n : L i o n ] [ l 1 l 2 ] : f i g h t ) ( d e f m e t h od e n c o u n t e r [ : Bunny : Bunny ] [ b1 b2 ] : mate ) ( d e f b1 { : S p e c i e s : Bunny } ) ( d e f b2 { : S p e c i e s : Bunny } ) ( def l 1 { : S p e c i e s : Lion }) ( def l 2 { : S p e c i e s : Lion }) ( encounter b1 b2 ) ==> : mate ( encounter b1 l1 ) ==> : run−away ( encounter l1 b1 ) ==> : eat ( encounter l1 l2 ) ==> : fight Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 17 / 34
18. Протоколы и типы данных Введены в версии 1.2 Быстрее чем мультиметоды Позволяют написать Clojure in Clojure Диспатчеризация только по типу данных Похожи на type classes в Haskell Создают соответствующие интерфейсы для Java defrecord & deftype объявляют новые типы данных extend-protocol & extend-type связывают протокол с типами данных (не только объявленными в Clojure!) reify – для реализации протоколов и интерфейсов для “одноразовых” типов Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 18 / 34
19. Пример протоколов ( d e f p r o t o c o l H e l l o " Test of p r o t o c o l " ( h e l l o [ t h i s ] " h e l l o function ")) ( d e f r e c o r d B [ name ] H e l l o ( h e l l o [ t h i s ] ( s t r " H e l l o " ( : name t h i s ) " ! " ) ) ) ( h e l l o (B . " U s e r " ) ) == " H e l l o U s e r ! " > ( e x t e n d −p r o t o c o l H e l l o S t r i n g ( hello [ this ] ( str " Hello " this "!"))) ( h e l l o " w o r l d " ) == " H e l l o w o r l d ! " > ( e x t e n d −p r o t o c o l H e l l o j a v a . l a n g . O b j e c t ( h e l l o [ t h i s ] ( s t r " H e l l o ’" t h i s " ’ ! (" ( type t h i s ) " ) " ) ) ) ( h e l l o 1 ) == " H e l l o ’ 1 ’ ! ( c l a s s j a v a . l a n g . I n t e g e r ) " > Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 19 / 34
20. Прочее Метаданные – #^{} в 1.0 и 1.1 или просто ^{} в 1.2 Опциональная спецификация типов (type hints) – #^Type или ^Type Спецификация тестов прямо в объявлении функции Управление областью видимости Программный доступ к метаданным Не влияют на равенство (equality) значений Пространства имен (namespaces) First-class objects Используются для организации кода в библиотеки Деструктуризация параметров функций и возвращаемых значений ( l e t [ [ a b & c : as e ] [1 2 3 4 ] ] [ a b c e ] ) == [ 1 2 ( 3 4 ) [ 1 2 3 4 ] ] > ( l e t [ { : k e y s [ a b c ] : a s m : o r {b 3}} { : a 5 : c 6 } ] [ a b c m] ) == [ 5 3 6 { : a 5 : c 6 } ] > Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 20 / 34
21. Взаимодействие с Java Двухстороннее взаимодействие с целевой платформой: Создание экземпляров классов Java – new или Class. Вызов кода, написанного на Java – ., .., doto Генерация классов и интерфейсов для вызова из Java – gen-class, gen-interface, proxy (анонимный класс) Возможность выполнения кода Clojure из программ на Java Отдельные функции для работы с массивами Java make-array – создание массивов aget/aset – доступ к элементам массивов amap/areduce – итерация по элементам массивов memfn позволяет использовать функции-члены классов в map, filter, . . . Спец. форма set! для установки значений в классе Генерация и перехват исключений – throw & catch Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 21 / 34
22. Примеры Создание объектов: ( new j a v a . u t i l . Date ) <== ( j a v a . u t i l . Date . ) > Доступ к полям/функциям членам классов: ( . s u b s t r i n g " H e l l o World " 0 5 ) == " H e l l o " > ( . " H e l l o World " s u b s t r i n g 0 5 ) == " H e l l o " > Math/ PI == 3 . 1 4 1 5 9 2 6 5 3 5 8 9 7 9 3 > ( I n t e g e r / p a r s e I n t " 4 2 " ) == 42 > .. для связанных вызовов: ( . . System g e t P r o p e r t i e s ( g e t " o s . name " ) ) == "Mac > System . g e t P r o p e r t i e s ( ) . g e t ( " o s . name " ) doto – вызов нескольких методов для одного объекта: ( d o t o ( j a v a . u t i l . HashMap . ) ( . p u t " a " 1 ) ( . p u t "b" 2 ) ) Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 22 / 34
23. Конкурентное программирование Средства, обеспечивающие изменяемость данных: Ссылки (refs) – синхронное, координированное изменение Агенты (agents) – асинхронное, независимое Атомы (atoms) – синхронное, независимое Переменные (vars) – изменение, локальное для нитей @ (deref) – используется для доступа к данным Параллельное выполнение кода: futures pmap & pcalls Native threads Средства синхронизации – promise Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 23 / 34
24. Ссылки & STM Координированное изменение данных из нескольких потоков Software Transaction Memory обеспечивает атомарность, целостность, изоляцию Изменения происходят только в рамках транзакции Возможность проверки данных с помощью функции-валидатора Возможность добавления функций-наблюдателей ( def counters ( r e f {})) ( d e f n get −c o u n t e r [ k e y ] ( @counters key 0)) ( d e f n i n c r e m e n t −c o u n t e r [ k e y ] ( dosync ( a l t e r c o u n t e r s a s s o c key ( i n c ( @counters key 0 ) ) ) ) ) Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 24 / 34
25. Агенты Асинхронное обновление данных – “fire and forget” Пулы потоков для выполнения функций обновления данных: send – для “быстрого” обновления данных, send-off – для “тяжелых” функций (отдельный пул потоков выполнения) send & send-off получают функцию, которая будет применена к текущему состоянию агента Функции-валидаторы и функции-наблюдатели Возможность ожидания окончания всех заданий агента ( def acounters ( agent {})) ( d e f n i n c r e m e n t −a c o u n t e r [ k e y ] ( send a c o u n t e r s a s s o c key ( i n c ( @counters key 0 ) ) ) ) ( d e f n get −a c o u n t e r [ k e y ] ( @acounters key 0)) Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 25 / 34
26. Vars & Атомы Атомы Синхронное изменение данных без координации Изменение данных производится функцией, которая применяется к текущему значению Функция может быть вызвана несколько раз, если кто-то уже изменил значение Функция не должна иметь побочных эффектов! Vars Обеспечивают изменение данных в рамках текущего потока binding связывает новые значения с символами Изменения затрагивают все вызываемые из текущего потока функции Будьте осторожны с ленивыми последовательностями! ( def ∗ var ∗ 5) ( defn foo [ ] ∗ var ∗) ( f o o ) == 5 > ( b i n d i n g [ ∗ v a r ∗ 1 0 ] ( f o o ) ) == 10 > Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 26 / 34
27. Параллельное выполнение кода future выполняет заданный код в отдельном потоке @ – для доступа к результатам выполнения кода @ блокирует текущий поток, если нет результатов promise используется для синхронизации между потоками данных deliver устанавливает значение @ читает установленное значение или блокирует выполнение, если оно не установлено pmap & pcalls – выгодно использовать только для “тяжелых” функций обработки данных. Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 27 / 34
28. Clojure в реальной жизни Инфраструктура и инструментальная поддержка: Среды разработки Средства сборки Библиотеки Репозитории кода Clojure/core – коммерческая поддержка, консультации и т.п. Использование в коммерческих проектах Источники информации Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 28 / 34
29. Инфраструктура: IDE и средства сборки Поддержка в большинстве IDE: Emacs + SLIME (самый популярный) VimClojure NetBeans Eclipse IntelliJ IDEA Утилиты сборки кода: Поддержка Clojure в Maven и Ant Leiningen – написан на Clojure, расширяемый и очень простой в использовании Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 29 / 34
30. Инфраструктура: библиотеки и репозитории Доступ к большому набору существующих библиотек Clojure-specific libraries: Clojure-Contrib Compojure ClojureQL Incanter и другие – см. http://clojars.org Репозитории: build.clojure.org clojars.org Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 30 / 34
31. Использование в коммерческих проектах Зарубежные проекты: FlightCaster ThinkRelevance Runa Sonian Networks BackType DRW Trading Group Snowtide Informatics Systems, Inc. - проект DocuHarvest ThorTech Solutions Несколько российских стартапов используют Clojure: ООО "Моделирование и Технологии" Security Technology Research (http://setere.com) Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 31 / 34
32. Источники информации Основные: Сайт проекта – http://clojure.org Planet Clojure – http://planet.clojure.in Канал #clojure на freenode.net Проект labrepl (http://github.com/relevance/labrepl) – учебная среда для изучения языка Try-Clojure (http://www.try-clojure.org/) – работа с кодом используя только Web-браузер Русскоязычные ресурсы: Русская планета ФП – http://fprog.ru/planet/ clojure at conference.jabber.ru Clojure форум на http://lisper.ru Мой сайт – http://alexott.net/ru/clojure/ Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 32 / 34
33. Источники информации Книги: Programming Clojure – 2009-й год, версия 1.0 Practical Clojure. The Definitive Guide – 2010, версия 1.2 The Joy of Clojure (beta) Clojure in Action (beta) Clojure Programming on Wikibooks Clojure Notes on RubyLearning Видео-лекции и скринкасты Группы пользователей по всему миру Учебные курсы (пока только в США и Европе) Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 33 / 34
34. Спасибо за внимание Вопросы Alex Ott (alexott@gmail .com) Язык Clojure MarginCon 2010 34 / 34