Clojure vs С# language
Я все еще пытаюсь понять явные преимущества clojure. Я понимаю, что это динамический, [почти] чисто функциональный язык, который хорошо подходит для модульного тестирования, concurrency и быстрого развития.
Я смотрел эту презентацию своим основателем Ричем Хики.
Вокруг отметки 25-й минуты вы можете увидеть множество замечательных способов, в которых clojure упрощает программирование благодаря возможности определять списки и векторы динамически:
( 123) [123]
способность использовать эти динамически определенные векторы как функции
([ 123] 0)
возможность вызова функций по вновь определенным строкам
(.ToUpperCase "foo")
как выразился Rich, "синтаксис для литералов - это синтаксис для языка".. красивый.
но не возможно ли сделать этот стиль программирования в .net 4.0? (хотя и более болтливый)
(new[] {1,2,3})[0]
"foo".ToUpper()
и т.д..net также может использоваться для программирования функциональным способом (хотя он не применяется)
это тривиальные примеры, но похоже, что это основа clojure. Каковы некоторые функции, которые устанавливают clojure больше друг от друга и делают его лучшим выбором в некоторых сценариях?
Ответы
Ответ 1
Я лично считаю, что синтаксис Clojure очень эффективен, краток и даже красив, как только вы его повесите. Однако, на мой взгляд, это не самая веская причина для выбора языка.
Мои личные причины для предпочтения Clojure как моего "языка выбора общего назначения выбора" после многих лет Java и С#:
-
Макро-метапрограммирование макроса - Clojure - это Lisp и наследует девиз семейства "Код - данные" Lisp. Поскольку сам язык написан в форме, которая сама является структурой данных внутри языка (это называется Homoiconicity), тривиально писать код, который генерирует код в любой форме, которую вы выберете. Вам никогда больше не нужно беспокоиться о "Design Patterns", если на языке, который вы хотите использовать, чего-то не хватает, вы просто расширяете язык с помощью макроса и двигаетесь дальше.
-
Динамический по умолчанию - Clojure по умолчанию является динамическим языком, что означает, что он автоматически "делает правильную вещь" гибким способом для большинства задач. Это приводит к повышению производительности. Примерами являются автоматическое переполнение для арифметики BigInteger, возможность размещения любых типов объектов, которые вам нравятся в коллекции, никогда не требующих объявления типов параметров и т.д. В то же время вы можете указать информацию о типе, чтобы повысить производительность, если это необходимо (напрямую используя примитивы или например, подсказки типов) - поэтому при необходимости вы можете получить очень быструю производительность.
-
Акцент на функциональное программирование с постоянными, неизменными структурами данных и ленивой оценкой - в частности, вся основная библиотека Clojure предназначена для поддержки этого стиля разработки по умолчанию. Как только вы его повесите (я признаю, что это нелегко...) FP исключительно мощный. Хотя вы можете эмулировать код "FP-style" практически на любом языке, вы действительно получаете только полные преимущества, когда это распространенная особенность языка (Clojure, Haskell, ML spring наиболее очевидно для ума)
-
Отличный многоядерный concurrency. Благодаря очень новой системе STM, я считаю, что Clojure имеет лучшую историю concurrency любого языка на данный момент (см. Этот видео для более подробной разработки Rich Сам Хикки)
-
экосистема с открытым исходным кодом. Я большой поклонник открытого исходного кода, а Clojure - это очень удобный язык с открытым исходным кодом. Сам язык и почти каждая библиотека имеют открытый исходный код, а если этого недостаточно для вас, то тривиально вызывать библиотеки Java. Учитывая широту всей экосистемы с открытым исходным кодом Java/JVM, это означает, что почти все, что вы хотите сделать, доступно в библиотеке (большое преимущество перед большинством новых языков!)
-
JVM-совместимость - вы можете или не заботитесь об этом, но лично это важная функция для меня, чтобы я мог интегрироваться с библиотеками и инструментами в юниверсе Java/JVM. Clojure делает это очень просто - объекты Clojure являются объектами JVM под капотом и вызов метода Java обычно прост как (.someMethod someObject someParameter)
-
Интерактивная разработка в стиле REPL - типичный стиль разработки Clojure - это взаимодействие с текущей программой Clojure в REPL. Вы можете переопределить практически все "на лету", не выполняя цикл компиляции/сборки/тестирования. Это потрясающе эффективный способ работы - я в основном создаю запущенную программу на REPL, а затем скопирую нужные команды в исходный файл, который будет запущен в будущем. Глупый пример. У меня есть однострочный, который способен визуализировать различные структуры данных из запущенной программы в диаграмме с использованием Incanter. Я могу сразу увидеть визуально, если что-то пойдет не так, и только это спасло мне недели отладки....
-
Сообщество. Мне лично нравится сообщество Clojure, которое мало, но быстро растет. Он получил правильное сочетание прагматизма (т.е. Делания), полезности и заботы о том, чтобы делать все хорошо, что, на мой взгляд, важно.
Ответ 2
Обоснование Clojure дает гораздо лучшие подробности, чем я могу, но моими причинами для обучения Clojure были:
- Macros - код - это данные, данные - код (homoiconic). Макросы дают вам возможность писать новый код во время компиляции и позволяют добавлять новый синтаксис на язык.
- Программная транзакционная память - STM позволяет писать код, не беспокоясь о деталях с низким уровнем concurrency. В программной транзакции среда выполнения Clojure обнаруживает, имеют ли две транзакции одни и те же данные, и откладывает одно и повторяет попытку.
- Интеграция с существующей виртуальной машиной - Благодаря возможности использования Java, Clojure автоматически получает доступ к миллионам строк хорошо протестированного кода.
Ответ 3
Clojure основные удобства над С#, грубо упорядоченные по уровню удобства, с самыми большими улучшениями в верхней части:
-
Более приятный синтаксис для литеральных коллекций, как вы заметили. В первую очередь для буквенных хеш-карт, которые достаточно уродливы в С# (вам нужно выписать общий тип), что вы не определяете один встроенный. С# new Dictionary<string, int> { { "Joe", 6" }, { "Steve", 18" } }
становится {"joe" 6, "steve" 18}
.
-
Мощное деструктурирование аргументов функции, которое хорошо работает с вышеупомянутым синтаксисом литерала коллекции.
-
Ключевые слова упрощают обращение к вещам символически, не требуя времени для определения перечислений.
-
В основной библиотеке есть много полезных встроенных модулей для функционального программирования, которые отсутствуют в LINQ.
-
В основной библиотеке есть действительно красивые неизменяемые векторы и карты, которые прекрасно работают вместе с вышеупомянутыми встроенными модулями.
-
Благодаря тому, что основные структуры данных неизменяемы, на языке действительно удобны транзакции STM для управления concurrency, которые работают без особых усилий.
-
Метаданные чрезвычайно удобны; он позволяет вам "прикоснуться" к информации, которая проходит вместе с другими данными таким образом, который намного проще, чем, например, определяя тип throwaway, представляющий исходные данные и данные других.
-
Часто вы хотите использовать абстракцию с типами, которые вы не контролируете; Clojure упрощают это, в то время как в С# это почти невозможно, поскольку вы не можете распространять кого-то другого для реализации интерфейса. (Вы даже не можете делать тривиальные вещи, например, сделать INumeric-интерфейс.)
-
Макросы проще в использовании и более мощные, чем деревья выражений С# для расширения языка.
Дополнительную информацию о большинстве упомянутых выше материалов можно найти в Clojure.org.
Ответ 4
([1 2 3] 0) не эквивалентен (new [] {1,2,3}) [0], поскольку в clojure [1 2 3] можно передать функции, которая принимает любую функцию который принимает int и возвращает значение. Например:
(defn do-something [mylist myfunc]
(map myfunc mylist))
(do-something [0 2] [1 2 3])
= > (1 3)
Это позволяет повторно использовать do-something с любой функцией, которая принимает 1 arg и возвращает значение.