30.8.10

Выпущен CEDET 1.0!

После многих лет разработки, бесчисленных версий 1.0preX, наконец-то выпущена версия 1.0 замечательного пакета для Emacs - CEDET.
Данная версия достаточно отличается от предыдущей - 1.0pre7, и содержит много изменений в Semantic, EDE и других подсистемах. Полный список изменений можно найти в официальном анонсе.
Пакет с исходным кодом можно скачать со страницы проекта и скомпилировать согласно инструкциям.
А после выпуска версии 1.0 продолжится работа над интеграцией пакета в Emacs, разработкой новых парсеров и унификацией подсистем Semantic.

19.8.10

Вышла Clojure 1.2

После 8 месяцев напряженной работы, вышла новая версия языка Clojure - 1.2.
В этой версии очень много изменений, из которых особо стоит отметить следующие:
  • добавлены протоколы (protocols) и типы данных (datatypes), позволяющие создавать новые абстракции и полиморфные функции. При этом производительность гораздо выше чем при использовании мультиметодов;
  • расширена деструктуризация структур данных, о которой я уже писал;
  • в составе языка введено несколько новых пространств имен, функции которых были перенесены из clojure-contrib. Сюда относятся функции для работы со строками, repl, pretty printer, ввод/вывод Java, и т.д.;
  • расширен набор функций для работы с последовательностями;
  • добавлена поддержка аннотаций Java, что позволяет использовать соответствующий функционал различных фреймворков;
  • много изменений, связанных с улучшением производительности кода;
  • для указания метаданных теперь вместо #^ используется просто ^.
Полный список изменений можно найти в репозитории языка. Также полезной может быть презентация Michael Fogus о новых возможностях.

P.S. я успел только частично обновить Введение в Clojure (это обновленная версия статьи из 4-го номера ПФП) описанием функциональности из версии 1.2. Сейчас не хватает описания протоколов и типов данных. Я надеюсь, что допишу этот кусок за выходные, о чем сделаю отдельный анонс

17.8.10

Подкастовое

Дебютировал в подкасте у golodnyj. Это первая часть в которой мы общаемся на тему функционального программирования и лиспа. Вторая часть (через несколько дней) будет про язык Clojure...

11.8.10

Русская планета Clojure

Я сделал (пока с помощью Yahoo! Pipes) агрегатор русскоязычных блогов, посвященных Clojure.  Все заведено через feedburner, так что будущие изменения в хостинге не будут влиять на подписчиков.
Если кто пишет про Clojure на русском - пишите мне, с ссылками на блог - я сразу добавлю.
Update 1: Что-то Yahoo! Pipes выставляет неправильные ссылки на оригинальные посты - разбираюсь с ним
Update 2: Починил

6.8.10

Деструктуризация параметров в Clojure

Это небольшое дополнение к статье про Clojure, которое я решил опубликовать отдельно. Эта часть будет добавлена в оригинальную статью, которая сейчас обновляется в предверии выхода Clojure версии 1.2.

Если вы передаете сложные структуры данных в функции (defn или fn), или связываете значения с символами в let, то вы можете использовать встроенную в Clojure деструктуризацию параметров, что позволяет связывать части структур данных с символами. Это значительно упрощает (и сокращает) код, поскольку вам не нужно писать явный код для получения значения значений из массивов или отображений.
Существует две формы деструктуризации параметров — деструктуризация отображений, и деструктуризация векторов, строк и массивов. Деструктуризация векторов/массивов/строк имеет простую форму — вы помещаете список символов внутри вектора, и значения, стоящие на соответствующих местах в деструктурируемом объекте, будут связаны с этими символами. В том случае, если вы укажете меньше аргументов, чем указано символов, то отсутствующие значения будут рассматриваться как имеющие значение nil, если укажете больше, то они будут отброшены. Вы можете собрать "лишние" значения в отдельный список, используя запись & символ, и все "лишние" значения будут помещены в список, связанный с указанным символом. Вот примеры использования деструктуризации векторов и строк:
user> (let [ [a b] [1 2]]
  (list a b))
(1 2)
user> (let [ [a b] [1]]
  (list a b))
(1 nil)
user> (let [ [a b] [1 2 3 4]]
  (list a b))
(1 2)
user> (let [ [a b & c] [1 2 3 4]]
  (list a b c))
(1 2 (3 4))
user> (let [ [a b & c] "abcde"]
  (list a b c))
(\a \b (\c \d \e))
user> ((fn [ [a b] ] (list a b)) [1 2])
(1 2)
user> (defn dfunc1 [ [a b] ]
  (list a b))
user> (dfunc1 [1 2])
(1 2)
Деструктуризация отображений выглядит следующим образом — вы записываете отображение, в котором ключом является символ, с которым будет связано значение, а значением — является ключ в деструктурируемом отображении. Например,
user> (let [{a :k1 b :k2 c :k3} {:k1 1 :k2 2 :k3 3}]
  (list a b c))
(1 2 3)
user> (let [{a :k1 b :k2 c :k3} {:k1 1 :k3 3}]
  (list a b c))
(1 nil 3)
Также как и в случае с деструктуризацией векторов, если конкретный ключ не был указан, то символ получает значение nil, как это видно во втором примере.
Деструктуризация отображений может иметь более сложную форму, поскольку можно указывать еще и значения по умолчанию, которые будут присвоены соответствующим символам вместо nil, если нужный ключ не был указан в отображении. Это осуществляется путем указания ключевого символа :or и отображения, в котором перечисляются значения по умолчанию:
user> (let [{a :a b :b c :c :or {a 1 b 2 c 3}} {:a 4}]
  (list a b c))
(4 2 3)
Для того, чтобы не писать пары символ/ключ, имеется упрощенная форма записи, когда вы указываете ключевой символ :keys и вектор, содержащий список символов, которые будут превращены в ключевые слова с теми же самыми именами, и которые будут использоваться для поиска ключей в деструктурируемом отображении. Например, предыдущие примеры можно переписать в более компактной форме:
user> (let [{:keys [a b c]} {:a 1 :b 2 :c 3}]
  (list a b c))
(1 2 3)
user> (let [{:keys [a b c]} {:a 1 :c 3}]
  (list a b c))
(1 nil 3)
Кроме ключевых символов, в качестве ключей отображений вы можете использовать строки и символы. Для этого нужно использовать ключевое слово :strs — для строк и :syms — для символов, как это показано в следующих примерах:
user> (let [{:strs [a b c] :as m :or {a 2 b 3}} {"a" 5 "c" 6}]
  (list a b c m))
(5 3 6 {"a" 5, "c" 6})

user> (let [{:syms [a b c] :as m :or {a 2 b 3}} {'a 5 'b 6}]
  (list a b c m))
(5 3 6 {"a" 5, "c" 6})
Особенно полезна деструктуризация отображений для тех случаев, когда вы хотите иметь необязательные (и именованные) параметры в функциях. В этом случае, объявление функции будет иметь вид
(defn имя-функции [обязательные параметры
         & {:keys [необязательные параметры]
            :or {значения по умолчанию}}]
тело функции)
например,
user> (defn dfunc2 [a b & {:keys [c d] :or {c "c" d "d"}}]
  (list a b c d))
user> (dfunc2 1 2 :c 3)
(1 2 3 "d")
Здесь мы определяем функцию, принимающую два обязательных параметра, и два необязательных, значения которых можно указывать после соответствующих ключевых символов.
Деструктуризация — это полезный инструмент, но иногда необходимо получить все переданные параметры в неизменном виде. Для этого можно использовать ключевой символ :as символ, которая связывает указанный символ с оригинальными параметрами. Например:
user> (let [[a b :as c] [1 2 3]]
  (list a b c))
(1 2 [1 2 3])
user> (let [{a :a b :b :as c} {:a 1 :b 2 :c 3}]
  (list a b c))
(1 2 {:a 1, :b 2, :c 3})
Также хочется отметить, деструктуризация может применяться и к вложенным структурам, например, если у вас есть вектор векторов, или вложенные отображения. Например,
user> (let [ [a [b c]] [1 [2 3]]]
  (list a b c))
(1 2 3)
user> (let [ [a [b c]] [1 2]]
  (list a b c))
Error....
user> (let [{a :a {c :c d :d} :b} {:a 1 :b {:c 3 :d 4}}]
  (list a c d))
(1 3 4)
Но тут стоит быть осторожным, поскольку если вместо вектора вы передадите объект несовместимого типа, то вы получите ошибку, как во втором примере.
Дополнительные примеры вы можете найти на данной странице. Также хорошее описание деструктуризации параметров можно найти в книге "Clojure in Action".