Пришлось мне столкнуться по-службе с Clojure. Мои впечатления от знакомства:
- Первое, что бросается в глаза — это дурацкие [] и {} вместо расово верных (). Не скажу, что они упрощают чтение кода, ИМХО разница невелика. А вот написание усложняют (по крайней мере мне). Набирать закрывающие сущее мучение; вылазит вот такое ))}))]) безобразие и сиди считай скобки. Так недалеко и до JavaScript с его вечными });});});
- Зато, эти же самые [] и {} позволяют сделать конфиг с симпатичным синтаксисом почти-JSON.
{
:listen {
:host "localhost"
:port 8080
}
:db {
:host "localhost"
:port 5432
:database "database"
:user "root"
:password "secret"
}
} - Жутко неудобно писать императивный код. Мутабельность здесь не любят. Код, конечно, от этого становится чище, но времени на написание уходит чуть больше.
- Нет многострочных комментариев. Пришлось написать reader macro, добавляющий комментарии в стиле Common Lisp.
(defn dispatch-reader-macro [ch fun]
(let [dm (.get (doto
(.getDeclaredField clojure.lang.LispReader
"dispatchMacros")
(.setAccessible true))
nil)]
(aset dm (int ch) fun)))
(defn read-comment [rdr pipe]
(loop [s nil]
(let [c (.read rdr)]
(if-not (and s (= c (int \#)))
(recur (= c pipe))))))
(dispatch-reader-macro \| read-comment)Единственное неудобство: нужно делатьrequire
во всех файлах, где эти комментарии используются. - Очень понравился Leiningen. Собрать с его помощью jar-файл и запустить его на сервере оказалось очень просто. Сделано "для людей".
18 комментариев:
По поводу 2) - не аргумент, равнозначный конфиг в CL
(
:listen (
:host "localhost"
:port 8080
)
:db (
:host "localhost"
:port 5432
:database "database"
:user "root"
:password "secret"
)
)
или даже можно читабельней ни разу не менее симпатичный:)
Дополнительный синтаксис усложняет кодогенерацию и вообще работу со списочными структурами, представляющими и код и данные.
Для работы со скобками очень удобно использовать paredit, или его аналоги в других редакторах.
Насчет мутабельности - к этому быстро привыкаешь, и как показывает практика, не так часто она и нужна. А вот с ленивостью - надо быть очень осторожным, до сих пор регулярно натыкаюсь на ошибки, особенно когда работаешь с каким-то явовским кодом внутри map или т.п.
@LinkFly
Разница в том, что пример на clojure можно eval-ить. Ну и закрывающие скобки в CL рука не поднимается переносить. :)
@Alex Ott
Не хватает терпения осиливать всевозможные плюшки emacs'а. Запомнил M-w и C-y и хватит :).
Мутабельность нужна очень редко вообще. Я даже на C++ старался писать иммутабельный код и чистые функции. Но я ж не настоящий сварщик, clojure взял в руки три дня назад. Не всё получается с первого раза написать правильно.
Ну и постоянно тянет всё переписывать, полировать код. Перфекционизм так и прёт. Написал doseq, переделал в loop/recur, потом заменил на reduce. Какое-то колесо сансары прям.
@Andy: ну paredit очень сильно облегчает работу, как минимум он тебе будет вставлять парные скобки, а потом уже можно и остальному научиться - я из него только пользуюсь Ctrl-arrow left/right, которые позволяют сдвигать скобки корректно
lazy-seq + java mutable api = butthurt
Да можно же ведь макросы чтения использовать и eval'ить себе на здоровье если надо. Только вот не надо:)
@LinkFly
Не надо никаких макросов.
Мне самому даже "(list ..." роднее чем эти "{", "[". :)
leiningen — это пипец: "шаг вправо, шаг влево — попытка к бегству". Попробуйте, например, сделать такую простую вещь, как добавить путь к java-библиотекам, которые находятся в двух разных директориях (например, lib и libs).
@Vsevolod: Lein очень легко патчится и расширяется, а автор охотно принимает патчи. Я туда засунул всю нужную мне функциональность...
@andy128k
[...] - вектор
(...) - список
{...} - мэп
#{..} - множество
разные вещи =)
[...] - список, с жесткими позициями
(...) - список,
{...} - список, нечетные позиции - ключи, четные позиции - значения, ну или список ячеек
#{..} - список, элементы повторяться не могут
Для многострочных комментариев можно использовать макрос comment из коробки.
user=> (comment )))
nil
java.lang.Exception: Unmatched delimiter: )
java.lang.Exception: Unmatched delimiter: )
user=> #| sadf |#
nil
user=> #| sadf |#|#
CompilerException java.lang.RuntimeException: Unable to resolve symbol: |# in this context, compiling:(NO_SOURCE_PATH:0)
nil
user=> #| sadf |#|#|#
CompilerException java.lang.RuntimeException: Unable to resolve symbol: |#|# in this context, compiling:(NO_SOURCE_PATH:0)
nil
user=>
Смешно. Вот только не по-делу совсем.
Этот comment то же самое что и (when false ...). Часто нужно закомментировать фрагмент кода с несбаллансированными скобками. А тратить время на скобки в комментарии -- это за гранью добра и зла.
Мне больше автоматический gensym в стиле var# понравился.
нужно проверить :)
Отправить комментарий