close

Клоун

Перейти к навигации Перейти к поиску
клоун
Логотип Clojure.svg
Разработчики)
Ричард Хики
https://clojure.org/
Главная Информация
Общие расширения clj, cljs, cljc, edn и cljr
Парадигма Функциональный , Мультипарадигмальный язык программирования
Появился в 2007 г.
Разработано Рич Хики
Последняя стабильная версия (2022-03-22)
система типов динамичный , сильный
Реализации JVM , CLR , JavaScript
под влиянием Lisp , ML , Haskell , Erlang Prolog
Операционная система Мультиплатформа
Лицензия Публичная лицензия Eclipse

Clojure — диалект языка программирования общего назначения Lisp . Особое внимание уделяется функциональной парадигме с целью (помимо прочего) устранения сложности, связанной с параллельным программированием . Clojure можно запускать поверх виртуальной машины Java и виртуальной машины платформы .NET , а также компилировать в JavaScript .

Принципы

Рич Хикки описывает разработку Clojure как поиск языка, который он не смог найти: рабочий лисп по умолчанию, построенный поверх надежной среды, а не собственной платформы, и с учетом параллельного программирования . [ 1 ]

Точно так же объектная ориентация отвергается в принципе, предлагая подход, при котором программы выражаются как применение функций к данным, а не как взаимодействие между изменяемыми сущностями, которые смешивают представление данных и поведение. С другой стороны, такие функции, как создание экземпляров, полиморфизм и интерфейсы, фактически являются частью языка.

Синтаксис

Как и остальная часть семейства Lisp, синтаксис Clojure построен на символических выражениях, которые перед компиляцией преобразуются в структуры данных программой чтения . Выражения характеризуются тем, что они разделены круглыми скобками и их префиксной нотацией, с помощью которой первый член каждого списка вызывается как функция, а остальные члены передаются в качестве аргументов.

Эта особенность, странная для тех, кто привык к наиболее популярным языкам, основанным на синтаксисе языка программирования C, лежит в основе его гибкости. Структуры данных, такие как карты , наборы и векторы , имеют буквальное выражение; они не требуют никакого преобразования при включении в синтаксическое дерево, сгенерированное компилятором. Clojure — это Lisp-1 , и он специально не предназначен для совместимости с другими lisps .

Макрос

Макрос — это фрагмент кода, который принимает другие выражения в качестве аргументов, не оценивая их, преобразуя их перед их вычислением. Это допускает появление «программ, создающих программы»: дополнения к языку — структуры управления потоком — или создание предметно-ориентированного языка . Возможности, в принципе недостижимые в других языковых семьях, не прибегая к разработке компилятора .

Система макросов Clojure очень похожа на Common Lisp , за исключением того, что версия обратной кавычки в Clojure (называемая «синтаксической кавычкой») определяет символы пространством имен, к которому они принадлежат. Это помогает предотвратить непреднамеренный захват, поскольку привязки с уточнением имени запрещены. Можно принудительно раскрыть макрос, который их захватывает, но это должно быть сделано явным образом. Clojure также запрещает повторное связывание глобальных имен в других пространствах имен, которые были импортированы в текущее.

Еще одна особенность синтаксической кавычки заключается в том, что она позволяет использовать систему шаблонов , в которой вы можете указать, какие члены списка должны оцениваться с помощью операторов раскатки (~) и раскавычивания-слияния (~@), что приводит к более кратким макросам и управляемый.

Особенности языка

  • Динамическая разработка с оценочной консолью ( REPL: read eval print loop ).
  • Представление функций в виде значений, а также предпочтение рекурсии и использование функций более высокого порядка по сравнению с итерацией на основе побочных эффектов .
  • Числа произвольной точности и буквальное представление дробей, генерируемых при нецелочисленных делениях.
  • Последовательности с ленивым вычислением (элементы последовательности не вычисляются до тех пор, пока они не потребуются, что позволяет представлять потенциально бесконечные множества).
  • Интегрированная система постоянных и неизменяемых структур данных.
  • Контроль состояния (набор значений, которые сущность может приобрести с течением времени) в ситуациях параллелизма через транзакционные системы, агентов и через локальные привязки .
  • Взаимодействие с java : благодаря компиляции в байт - код JVM приложения, написанные на Clojure, могут быть легко интегрированы в серверы приложений или другие среды Java с небольшой дополнительной сложностью. Все возможные интерфейсы на уровне класса, структуры данных и параллелизма реализованы по умолчанию, чтобы свести к минимуму усилия, необходимые для достижения этой переносимости.

Примеры

Привет мир . Обратите внимание, что из-за природы REPL команда печати не требуется .

"Привет, мир!"

Генератор уникальных и последовательных номеров, поддерживающий одновременные вызовы:

( let  [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* muted."   
  [&  forms] 
  ` ( binding  [*out*  bit-bucket-writer] 
     ~@forms ))

( noprint 
 ( println  "Здравствуйте, никто!" ))

В этом примере десять потоков управляют общей структурой данных, которая состоит из ста векторов, содержащих десять последовательных начальных уникальных номеров. Каждый поток выбирает две случайные позиции в двух случайных векторах и меняет их местами. Все изменения векторов выполняются внутри транзакций с использованием системы транзакционной памяти программного обеспечения Clojure . Вот почему даже после тысячи итераций ни одно число не потеряется.

( defn  run  [nvecs  nitems  nthreads  niters] 
  ( let  [vec-refs  ( vec  ( map  ( comp  ref  vec ) 
                           ( partition  nitems  ( range  ( *  nvecs  nitems ))))) 
        swap  #( let  [v1  ( rand-int  nvecs ) 
                    v2  ( rand-int  nvecs ) 
                    i1  ( rand-int  nvecs ) 
                    i2  ( rand-int  nitems ) ] 
                ( dosync 
                 ( let  [temp  ( nth  @ ( vec-refs  v1 )  i1 ) ] 
                   ( alter  ( vec-refs  v1 )  assoc  i1  ( nth  @ ( vec-refs  v2 )  i2 )) 
                   ( alter  ( vec-refs  v2 )  assoc  i2  temp )))) 
        report  #( do 
                 ( prn  ( map  deref  vec-refs )) 
                 ( println  "Distinct:" 
                          ( count  ( отличный  ( применить  concat  ( map  deref  vec-refs )))))) ] 
    ( отчет ) 
    ( dorun  ( применить  pcalls  ( повторить  nthreads  #( dotimes  [_  niters]  ( swap ))))) 
    ( отчет )))

( прогон  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] 00 
Различие:  00

Библиография

Внешние ссылки

Ссылки

  1. ^ «Основные принципы» . Рич Хики (на английском языке) . Проверено 17 октября 2008 г., здесь нет парадигмы .