Paradigm | мультипарадигмальный : |
---|---|
Семейство | Lisp |
Разработано | Ричем Хикки |
Впервые появилось | 2007; 13 лет назад (2007 г.) |
Стабильный выпуск | 1.10.1 / 6 июня 2019 г.; 16 месяцев назад (06.06.2019) |
Предварительный выпуск | 1.10.2-alpha1 / 5 марта 2020 г.; 7 месяцев назад (2020-03-05) |
Дисциплина ввода | |
Платформа | |
Лицензия | Общественная лицензия Eclipse |
Расширения имен файлов |
|
Веб-сайт | clojure.org |
Под влиянием | |
Под влиянием | |
|
Clojure (, как закрытие) - это современный, динамический и функциональный диалект языка программирования Lisp на платформе Java. Как и другие диалекты Lisp, Clojure обрабатывает код как данные и имеет систему макросов Lisp. Текущий процесс разработки управляется сообществом, и его наблюдает Рич Хики как его доброжелательный диктатор на всю жизнь (BDFL).
Защитники Clojure неизменяемость и неизменяемые структуры данных и побуждает программистов четко описывать управление идентичностью и ее состояниями. Этот акцент на программировании с неизменяемыми значениями и явными конструкциями прогрессии времени предназначен для облегчения разработки более надежных, особенно параллельных, программ, которые являются простыми и быстрыми. Хотя его система типов полностью динамическая, недавние усилия также были направлены на реализацию постепенного набора текста.
Коммерческая поддержка Clojure обеспечивается Cognitect. Ежегодно по всему миру организуются конференции Clojure, самая известная из которых - Clojure / con.
Рич Хики - создатель языка Clojure. До Clojure он разработал dotLisp, аналогичный проект, основанный на платформе .NET, и три предыдущих попытки обеспечить взаимодействие между Lisp и Java : интерфейс иностранного языка Java для Common Lisp (jfli), интерфейс внешних объектов для Lisp (FOIL) и дружественный к Lisp интерфейс для Java-сервлетов (Lisplets).
Хикки потратил около 2,5 лет, работая над Clojure, прежде чем опубликовать его публично, большую часть времени работаю исключительно над Clojure без внешнего финансирования. В конце этого времени Хикки отправил электронное письмо с описанием языка некоторым друзьям из сообщества Common Lisp.
Процесс разработки управляется сообществом и управляется на странице проекта Clojure JIRA. Общее обсуждение разработки происходит в Clojure Google Group. Кто угодно может отправлять вопросы и идеи на ask.clojure.org, но для внесения исправлений необходимо подписать соглашение с участником Clojure. Проблемы JIRA обрабатываются командой проверяющих, и, наконец, Рич Хики одобряет изменения.
Имя Clojure, по словам Хики, является каламбуром по концепции программирования «закрытие ", включающий буквы C, L и J для C#, Lisp и Java соответственно - трех языков, которые оказали большое влияние на дизайн Clojure.
Рич Хики разработал Clojure, потому что ему нужен был современный Lisp для функционального программирования, симбиотический с установленной платформой Java и предназначенный для параллелизм.
Подход Clojure к состоянию характеризуется концепцией идентичностей, которые представлены в виде серии неизменяемых состояний во времени. Поскольку состояния являются неизменяемыми значениями, любое количество рабочих процессов может работать с ними параллельно, и параллелизм становится вопросом управления изменениями из одного состояния в другое. Для этой цели Clojure предоставляет несколько изменяемых ссылочных типов, каждый из которых имеет четко определенную семантику для перехода между состояниями.
Версия | Дата выпуска | Основные функции / улучшения |
---|---|---|
16 октября 2007 г. | Первоначальный общедоступный выпуск | |
1.0 | 4 мая 2009 г. | Первый стабильный выпуск |
1,1 | 31 декабря 2009 г. | Фьючерсы |
1,2 | 19 августа 2010 г. | Протоколы |
1,3 | 23 сентября 2011 г. | Расширенная поддержка примитивов |
1,4 | 15 апреля 2012 г. | Литералы чтения |
1,5 | 1 марта 2013 г. | Редукторы |
1.5.1 | 10 марта 2013 г. | Устранение утечки памяти |
1.6 | 25 марта 2014 г. | Java API, улучшенные алгоритмы хеширования |
1,7 | 30 июня 2015 г. | Преобразователи, условия считывания |
1,8 | 19 января 2016 г. | Дополнительные строковые функции, прямое связывание, сервер сокетов |
1.9 | De 8 сентября 2017 г. | Интеграция со спецификациями и инструментами командной строки |
1.10 | 17 декабря 2018 г. | Улучшенный отчет об ошибках, совместимость с Java |
Текущая стабильная версия : 1.10.1 | 6 июня 2019 г. | Работа над снижением производительности Java и улучшение отчетов об ошибках из clojure.main |
Условные обозначения: Старая версия Старая версия, все еще поддерживается Последняя версия Последняя предварительная версия Будущий выпуск |
Clojure работает на платформе Java и, как следствие, интегрируется с Java и полностью поддерживает вызов кода Java из Clojure, а также код Clojure можно вызывать из Java. Сообщество использует Leiningen для автоматизации проектов, обеспечивая поддержку интеграции Maven. Leiningen обрабатывает управление пакетами проекта и зависимости и настраивается с использованием синтаксиса Clojure.
Как и большинство других Lisp, синтаксис Clojure построен на S-выражениях, которые сначала анализируются в структуры данных читателем перед компилируется. Средство чтения Clojure поддерживает буквальный синтаксис для карт, наборов и векторов в дополнение к спискам, и они компилируются непосредственно в упомянутые структуры. Clojure - это Lisp-1, и он не предназначен для кодовой совместимости с другими диалектами Lisp, поскольку он использует свой собственный набор структур данных, несовместимых с другими Lisp.
Как Lisp На диалекте Clojure поддерживает функции как первоклассные объекты, цикл чтения – оценки – печати (REPL) и систему макросов. Система макросов Lisp в Clojure очень похожа на систему Common Lisp, за исключением того, что версия Clojure обратной кавычки (называемая "синтаксическая кавычка") квалифицирует символы с их пространство имен. Это помогает предотвратить непреднамеренный захват имен, поскольку привязка к именам, определенным пространством имен, запрещена. Можно принудительно развернуть захват макроса, но это должно быть сделано явно. Clojure не позволяет создавать макросы для чтения, определяемые пользователем, но программа для чтения поддерживает более ограниченную форму синтаксического расширения. Clojure поддерживает мультиметоды, а для интерфейса -подобные абстракции имеют протокол, основанный на полиморфизме и системе типов данных с использованием записей, обеспечивая высокую производительность и динамический полиморфизм, разработанный, чтобы избежать проблемы выражения ..
Clojure поддерживает ленивые последовательности и поддерживает принцип неизменяемости и постоянных структур данных. В качестве функционального языка упор делается на рекурсию и функции высшего порядка вместо цикла на основе побочных эффектов. Оптимизация автоматического хвостового вызова не поддерживается, поскольку JVM не поддерживает ее изначально; это можно сделать явно, используя ключевое слово recur
. Для параллельного и параллельного программирования Clojure предоставляет программную транзакционную память, реактивную агентскую систему и канал на основе параллельное программирование.
Clojure 1.7 представила условия для чтения, разрешив встраивание кода Clojure и ClojureScript в одно и то же пространство имен. Преобразователи были добавлены как метод построения преобразований. Преобразователи позволяют выполнять функции высшего порядка, такие как map и fold, для обобщения по любому источнику входных данных. Хотя традиционно эти функции работают с последовательностями, преобразователи позволяют им работать с каналами и позволяют пользователю определять свои собственные модели для трансдукции.
Основная платформа Clojure - это Java, но существуют и другие целевые реализации. Наиболее заметными из них являются ClojureScript, который компилируется в ECMAScript 3, и ClojureCLR, полный порт на платформе .NET, совместимый с его экосистемой. Опрос сообщества Clojure с участием 1060 респондентов, проведенный в 2013 году, показал, что 47% респондентов использовали Clojure и ClojureScript при работе с Clojure. В 2014 году это число увеличилось до 55%, в 2015 году, исходя из 2445 респондентов, - до 66%. Популярные проекты ClojureScript включают реализации библиотеки React, такие как Reagent, re-frame, Rum и Om.
Другие реализации Clojure на различных платформах включают :
Благодаря постоянному интересу к функциональному программированию, использование Clojure разработчиками программного обеспечения, использующими платформу Java, продолжало расти. Язык также рекомендован разработчиками программного обеспечения, такими как Брайан Гетц, Эрик Эванс, Джеймс Гослинг, Пол Грэм и Роберт К. Мартин. . ThoughtWorks, оценивая функциональные языки программирования для своего Technology Radar, описал Clojure как «простую и элегантную реализацию Lisp на JVM» в 2010 году и повысил его статус до «ADOPT» в 2012 году.
В «Отчет об экосистеме JVM за 2018 год» (который был объявлен «крупнейшим опросом разработчиков Java»), который был подготовлен в сотрудничестве Snyk и Java Magazine, поставил Clojure на 2-е место среди наиболее часто используемых языков программирования на JVM для «основных Приложения". Clojure используется в промышленности такими фирмами, как Apple, Atlassian, Funding Circle, Netflix, Puppet, и Walmart, а также правительственные агентства, такие как NASA. Он также использовался для творческих вычислений, включая визуальное искусство, музыку, игры и поэзию.
Инструменты для разработки Clojure за прошедшие годы значительно улучшились. Ниже приведен список некоторых популярных IDE и плагинов, которые добавляют поддержку разработки Clojure:
Помимо инструментов, предоставляемых сообществом, официальные инструменты Clojure CLI также стали доступны в GNU / Linux, macOS и Windows начиная с Clojure 1.9.
Следующие примеры можно запустить в Clojure REPL, например, запущенном с инструменты CLI Clojure или интерактивный REPL, например, доступный на REPL.it.
Из-за сильного упора на простоту типичные программы Clojure состоят в основном из функций и простых структур данных ( т.е. списки, векторы, карты и множества):
;; Типичная точка входа в программу Clojure: ;; `-main` function (defn -main; name [args]; (переменная) параметры (println" Hello, World! ")); body
Как и другие Lisps, одной из характерных особенностей Clojure является интерактивное программирование на REPL. Обратите внимание, что в следующих примерах ;;
начинает строковый комментарий, а ;; =>
означает вывод:
;; определить var (def a 42) ;; =># 'user / a ;; вызвать функцию с именем `+` (+ a 8) ;; =>50 ;; вызвать функцию с именем ʻeven? `(even? a) ;; =>правда ;; определить функцию, которая возвращает остаток от `n` при делении на 10 (defn foo [n] (rem n 10)) ;; =># 'user / foo ;; вызвать функцию (foo a) ;; =>2 ;; вывести строку документации `rem` (doc rem) ;; =>------------------------- clojure.core / rem ([num div]) остаток от деления числителя на знаменатель. ;; распечатать источник `rem` (source rem) ;; =>(defn rem "остаток от деления числителя на знаменатель." {: добавлено "1.0": static true: inline (fn [xy] `(. clojure.lang.Numbers (остаток ~ x ~ y)))} [число div] (. clojure.lang.Numbers (остаток num div)))
В отличие от других сред выполнения, где имена компилируются, среда выполнения Clojure легко подвергается анализу с помощью обычных структур данных Clojure:
;; определить var (def a 42) ;; =># 'user / a ;; получить карту всех общедоступных варов, интернированных в пространство имен ʻuser` (пользователь ns-publics) ;; =>{a # 'user / a} ;; ссылаться на переменную через `# '` (макрос чтения) и ;; связанный с ним символ с указанием пространства имен ʻuser / a` # 'user / a ;; =># 'user / a ;; разорвать ссылку (получить значение) переменной var (deref # 'user / a) ;; =>42 ;; определить функцию (со строкой документации), которая ;; возвращает остаток от `n` при делении на 10 (defn foo" возвращает `(rem n 10)` "[n] (rem n 10)) ;; =># 'user / foo ;; получить метаданные переменной `# 'user / foo` (meta #' user / foo) ;; =>{: arglists ([n]),: doc "возвращает` (rem n 10) `",: line 1,: column 1,: file "user.clj",: name foo,: ns #namespace [user ]}
Подобно другим Лиспам, Clojure является гомоиконным (также известный как код как данные ). В приведенном ниже примере мы видим, насколько легко написать код, изменяющий сам код:
;; вызвать функцию (код) (+ 1 1) ;; =>2 ;; процитировать вызов функции ;; (превращение кода в данные, которые представляют собой список символов) (quote (+ 1 1)) ;; =>(+ 1 1) ;; получить первый элемент в списке ;; (работа с кодом как с данными) (first (quote (+ 1 1))) ;; =>+ ;; получить последний элемент в списке ;; (работает с кодом как с данными) (last (quote (+ 1 1))) ;; =>1 ;; получить новый список, заменив символы в исходном списке ;; (манипулирование кодом как данными) (map (fn [form] (case form 1 'one +' plus)) (quote (+ 1 1))) ;; =>(плюс один)
Макросы потоковой передачи (->
, ->>
и другие) могут синтаксически выражать абстракцию конвейерной передачи коллекции данных через серия преобразований:
(->>(диапазон 10) (карта inc) (фильтровать четные?)) ;; =>(2 4 6 8 10)
Этого также можно добиться более эффективно, используя преобразователи:
(последовательность (comp (map inc) (filter even?)) (Range 10)) ;; =>(2 4 6 8 10)
A Поточно-ориентированный генератор уникальных серийных номеров (хотя, как и многие другие диалекты Лиспа, Clojure имеет встроенный gensym
функция, которую он использует внутри):
(def i (atom 0)) (defn generate-unique-id "Возвращает отдельный числовой идентификатор для каждого вызова." (Swap! I inc))
Анонимный подкласс java.io.Writer
, который ни во что не записывает, и макрос, использующий его для отключения всех отпечатков в нем:
(def bit -bucket-writer (proxy [java.io.Writer] (write [buf] nil) (close nil) (flush nil))) (defmacro noprint "Оценивает данные` формы` со всеми выводами на `* out *` без звука. "[forms]` (binding [* out * bit-bucket-writer] ~ @ forms)) (noprint (println "Привет, никто!")) ;; =>nil
Clojure был создан с нуля, чтобы охватить свои хост-платформы как одну из целей разработки и, таким образом, обеспечить отличное взаимодействие языка с Java:
;; вызвать метод экземпляра (.toUpperCase "apple") ;; =>«ЯБЛОКО» ;; вызвать статический метод (System / getProperty "java.vm.version") ;; =>«12 + 33» ;; создать экземпляр `java.util.HashMap` и ;; добавить несколько записей (doto (java.util.HashMap.) (.put "яблоко" 1) (.put "банан" 2)) ;; =>{"банан" 2, "яблоко" 1} ;; создать экземпляр `java.util.ArrayList` и ;; увеличивайте его элементы с помощью `clojure.core / map` (def al (doto (java.util.ArrayList.) (.add 1) (.add 2) (.add 3))) (map inc al) ;; =>(2 3 4) ;; показать диалоговое окно сообщения с использованием Java Swing (javax.swing.JOptionPane / showMessageDialog nil "Hello, World!") ;; =>nil
10 потоков, управляющих одной общей структурой данных, которая состоит из 100 векторов, каждый из которых содержит 10 (изначально последовательных) уникальных чисел. Затем каждый поток несколько раз выбирает две случайные позиции в двух случайных векторах и меняет их местами. Все изменения векторов происходят в транзакциях с использованием программной транзакционной памяти Clojure system:
(defn run [nvecs nitems nthreads niters] (let [vec-refs (->>(* nvecs nitems) (диапазон) (в (comp (partition-all nitems) (map vec) (map ref)))) swap # (let [v1 (rand-int nvecs) v2 (rand-int nvecs) i1 (rand-int nitems)) i2 (rand-int nitems)] (dosync (let [tmp (nth @ (vec-refs v1) i1)] (alter (vec-refs v1) assoc i1 (nth @ (vec-refs v2) i2)) ( alter (vec-refs v2) assoc i2 tmp)))) report # (->>vec-refs (into (comp (map deref) (map (fn [v] (prn v) v)) cat (Different))) (count) (println "Distinct:"))] (report) (->># (dotimes [_ niters] (swap)) (repeat nthreads) (apply pcalls) (dorun)) (report))) (run 100 10 10 100000) ;; =>[0 1 2 3 4 5 6 7 8 9] [10 11 12 13 14 15 16 17 18 19]... [990 991 992 993 994 995 996 997 998 999] Отдельно: 1000 [382 318 466 963 619 22 21 273 45 596] [808 639 804 471 394 904 952 75 289 778]... [484 216 622 139 651 592 379 228 242 355] Отдельно: 1000 ноль