Clojure (язык программирования)

Материал из Национальной библиотеки им. Н. Э. Баумана
Последнее изменение этой страницы: 23:18, 8 июня 2016.
Clojure
Парадигма функциональный, мультипарадигмальный
Спроектировано Рич Хикки
Печать дисциплины динамическая, строгая
Лицензия Eclipse Public License
Портал: http://clojure.org
Влияние
Elixir

Введение

Clojure (произносится [ ˈkləʊ.ʒər ]) является диалектом языка программирования Lisp, созданный Rich Hickey. Clojure это язык программирования общего назначения с акцентом на функциональном программировании. Он работает в Java Virtual Machine, Common Language Runtime, и JavaScript engines. Как и другие Лиспы, Clojure рассматривает код как данные и имеет систему макросов. В настоящее время процесс развития community-driven, под контролем Rich Hickey как его основателя.

Статус

Последняя стабильная версия Clojure (на 11 декабря, 2015) 1.7, выпущенная 30 июня 2015 года. Первый стабильный релиз была версия 1.0, выпущенная 4 мая 2009 года. Clojure – это свободное программное обеспечение, распространяемое по лицензии Eclipse Public.

Особенности

  • Clojure работает в виртуальной машине Java, и как результат интегрируется с Java и полностью, поддерживает вызов Java кода из Clojure, и Clojure код может быть также вызван из Java
  • Синтаксис Clojure построен на S-выражениях, которые сначала разбираются в структуры данных с помощью считывателя перед компиляцией
  • Как диалект Lisp'a, Clojure поддерживает функции как объекты первого класса, петли read-eval-print, и макро-системы.
  • Clojure имеет поддержку для ленивых последовательностей и поощряет принцип неизменности и постоянных структур данных
  • Недавно Clojure ввел читатель конструкций, с помощью которых можно встраивать код Clojure и ClojureScript в одном и том же пространстве имен

Обзор

Hello world:

(println "Hello world!")

Определение функции:

(defn square [x]
  (* x x))

GUI "Hello world" через вызов библиотеки Java Swing:

(javax.swing.JOptionPane/showMessageDialog nil "Hello World" )

Установка

Синтаксис и семантика

Clojure – это современный вариант Lisp-1.

Основные типы данных

Числа: Clojure имеет целые числа, числа с плавающей запятой, и коэффициенты.

  • Целые включают десятичных чисел (255), восьмеричные числа (012), шестнадцатеричные числа (0xff), и числа с основанинием системы счисления (2r1111), где основание от 2 до 36
  • Числа с плавающей точкой включают в себя стандартные обозначения ( 3.1416 ) и научной нотации ( 1.35e-12 ).
  • Коэффициенты – это "функции" которые не эквивалентны целым числам, как, например 1/3. Они не подвержены ошибке округления.

Атомы (переменные): Имена для значений. Clojure допускает большую часть не алфавитно-цифровых символов в именях (но не круглые, квадратные или фигурные скобки).

Важные атомы: true, false, и nil. В состоянии, nil ведет себя как false; но nil не эквивалетно пустому list, ().

Строки заключены в двойные ковычки, и могут содержать экранированные символы: "hello", "line one\nline two".

Регулярные выражения пишутся как хэш-символ перед строкой: #"[a-z]+". Обратные косые черты не нужно удваивать.

Ключевые слова – это не зарезервированные слова (как while в Java), но как "атомы" в Прологе или Ерланге. Ключевое слово начинается с двоеточия (:foo) и обозначает само себя. Ключевые слова часто используются как ключи в хэшах.

Список – это последовательность значений, разделенных через пробел (включая запятые) и обрамленная круглыми скобками.

  • Вызовы функций записываются как список.
    • Первый элемент списка является именем функции, и последующие элементы являются аргументами функции, например (max 23 92 17).
  • Списки, которые не представляют функции, должны быть в кавычках. Список может быть '(1 2 3) or (quote (1 2 3)).

Вектор – это последовательность значений, заключенная в квадратные скобки, например [1 2 "buckle my shoe"], или эквивалентно, (vector 1 2 "buckle my shoe"). Элементы вектора разделены пробелами, включая запятые. Векторы используются, чтобы приложить формальные параметры функции.

Map или hash – это последовательность пар ключ/знчение, заключенные в фигурные скобки, например, {:ace 1, :deuce 2, "trey" 3}. Элементы разделены пробелами или запятыми. Полезно использовать запятые между парами.

Set – это знак (#) сопровождающийся последовательностью значений, залюченная в скобки, например #{a b c}.

Комментарии начинаются с запятой и продолжаются до конца строки.

Clojure также имеет функции, специальные формы и макросы.

Арифметика

  • +   Возвращает сумму аргументов; (+) возвращает 0
  • -   Вычитает оставшиеся числа из первого
  • *   Возвращает произведение аргументов; (*) возвращает 1.
  • /   Делит первое число на оставшиеся числа
    • Если операнды целые числа, результатом является соотношение
    • Если только одно число, возвращает его обратное
  • quot   Возвращает частное от деления нацело первого числа на остальных цифр
  • rem    Остаток от деления первого числа на второе
  • mod    Модуль первого и второго ряда; усечены к отрицательной бесконечности
  • inc    Возвращает число на один больше, чем его аргумент
  • dec    Возвращает число на один меньше, чем его аргумент
  • max    Возвращает наибольшее из своих аргументов
  • min    Возвращает наименьшее из своих аргументов
  • int    Обрезает число с плавающей точкой и возвращает целое значение символа
  • float  Преобразует целое число в число с плавающей точкой

Логика

Эти функции обрабатывают nil и false как false, остальное (включая пустой список) расценивается как true.

  • (and arg*)      Возвращает nil или false, если есть аргументы, в противном случае возвращает последний аргумент (макрос, не функция)
  • (or arg*)        Возвращает первое значение, которое не false или nil, или возвращает false или nil
  • (not arg)             Возвращает true если аргумент false, и наоборот

Ввод/вывод

Подробнее: input/output

Определение макросов

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

Clojure macro имеет сходтсво с функцией, но с этими различиями:

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

Следующие примеры из Practical Clojure by Luke VanderHart and Stuart Sierra.

(defmacro triple-do [form] ; makes three copies of the form
    (list 'do form form form) )

The call (triple-do (print "Hello ")) prints "Hello Hello Hello " and returns nil.

Формы macroexpand и macroexpand-1 каждый принимает вызов макроса в ковычках, и возвращает раскрытый макрос; macroexpand-1 раскрывает рекурсивный макрос только один раз. Например, (macroexpand '(triple-do (print "Hello "))) возвращает (do (print "Hello ") (print "Hello ") (print "Hello ")).

Взаимодействие с Java

Clojure может использовать объекты Java, методы и поля. Это включает в себя типы данных коллекции Java, хотя типы данных Clojure являются предпочтительными, поскольку они являются неизменными и постоянными. Возможно, лучшее использование Java в Clojure – это сделать Swing-GUI.

  • (import import-lists*)

Импортирует именованные Java классы. Например: (import '(java.awt.Color) '(java.awt.Point)).

Только классы могут быть импортированы, а не целые пакеты; нет эквивалента import java.util.*;

Весь java.lang неявно импортирован, наряду с clojure.core.

  • (new JavaClassName args*) (JavaClassName. args*) ; Синтаксический сахар для того

Создает и возвращает новый объект Java указанного класса. Например: (def rnd (new java.util.Random)), (def c (java.awt.Color. 255 128 0))

  • (. JavaObject methodName args*) (.methodName JavaObject args*)

Вызывает метод объекта Java с указанными аргументами. Например: (. rnd nextInt 10), (.nextInt rnd 10).

  • (. JavaObject fieldName)

Возвращает значение в поле Имя объекта Java. Например: после (def p (new java.awt.Point 20 40)), (. p x) будет возвращено 20.

  • (JavaClass/staticMethodName args*)

Вызывает статический метод класса. Например: (System/currentTimeMillis).

  • JavaClass/staticFieldName

Возвращает значение в статическом поле класса. Например: (java.awt.Color/CYAN).

  • doto(JavaInstanceOrClass methodCalls*)

Использует объект Java или класс как приемник для любого количества вызовов методов. Например: (doto (new java.util.HashMap) (.put "a" 1) (.put "b" 2)).

  • (proxy [Class? Interfaces*] [constructorArgs*] functions*)
(. convert-button
  (addActionListener
    (proxy [ActionListener] []
      (actionPerformed [evt]
        (let [c (Double/parseDouble (. temp-text (getText)))]
          (. fahrenheit-label
            (setText (str (+ 32 (* 1.8 c)) " Fahrenheit"))))))))

Есть также функции для работы с массивами Java, а также для обработки методов Java как объектов первого класса. Они здесь не рассматриваются.

Руководство по стилю

Это Clojure руководство по стилю рекомендует лучшие практики написания кода, так что одни Clojure программисты смогут писать код, который сможет поддерживаться другими Clojure программистами. Руководство по стилю отражает мировые практики, и поддерживает идеалы, отвергнутые людьми, дабы помочь избежать риски вообще – независимо от того, насколько это хорошо. Еще: The Clojure Style Guide on Github

Ссылки