C # Dev - я пробовал Лиспс, но не получаю [закрыто]

37

После нескольких месяцев изучения и игры с Lisp, как с CL, так и с немного Clojure, я все еще не вижу веской причины что-либо писать в нем вместо C #.

Мне бы очень хотелось, чтобы были веские причины, или чтобы кто-то указывал, что мне не хватает чего-то действительно большого .

Сильные стороны Лиспа (согласно моим исследованиям):

  • Компактная, выразительная запись - больше, чем C #, да ... но я, похоже, тоже могу выразить эти идеи в C #.
  • Неявная поддержка функционального программирования - C # с методами расширения LINQ:
    • mapcar =. Выбрать (лямбда)
    • mapcan = .Select (лямбда) .Aggregate ((a, b) => a.Union (b))
    • автомобиль / первый = .First ()
    • cdr / rest = .Skip (1) .... и т. д.
  • Поддержка лямбда-функции и функции высшего порядка - в C # есть это, и синтаксис, возможно, проще:
    • "(лямбда (х) (тело))" против "х => (тело)"
    • "# (" с "%", "% 1", "% 2" хорошо в Clojure
  • Диспетчеризация методов отделена от объектов - в C # есть методы расширения
  • Диспетчеризация мультиметода - C # не имеет этого изначально, но я мог бы реализовать это как вызов функции через несколько часов
  • Код - это данные (и макросы). Возможно, я не «получил» макросы, но я не видел ни одного примера, где идея макроса не могла бы быть реализована как функция; это не меняет "язык", но я не уверен, что это сила
  • DSLs - может сделать это только через композицию функций ... но это работает
  • Нетипизированное «исследовательское» программирование - для структур / классов, автообъекты C # и «объект» работают достаточно хорошо, и вы можете легко перейти к более сильной типизации по мере продвижения
  • Работает на оборудовании, отличном от Windows - Да, так? Вне колледжа я знал только одного человека, который не запускал Windows дома, или хотя бы виртуальную машину Windows на * nix / Mac. (Опять же, может быть, это важнее, чем я думал, и мне только что промыли мозги ...)
  • REPL для восходящего дизайна - хорошо, я признаю, что это действительно очень приятно, и я скучаю по нему в C #.

Вещи, которые мне не хватает в Лиспе (из-за сочетания C #, .NET, Visual Studio, Resharper):

  • Пространства имен. Даже со статическими методами мне нравится привязывать их к «классу», чтобы классифицировать их контекст (похоже, что у Clojure это есть, а CL нет).
  • Отличная поддержка компиляции и разработки
    • система типов позволяет мне определить «правильность» структур данных, которые я передаю
    • все, что написано с ошибками, указывается в реальном времени Я не должен ждать до времени выполнения, чтобы знать
    • улучшения кода (такие как использование подхода FP вместо императивного) выполняются автоматически
  • Инструменты разработки графического интерфейса: WinForms и WPF (я знаю, что Clojure имеет доступ к библиотекам Java GUI, но они мне совершенно чужды).
  • Инструменты отладки графического интерфейса пользователя: точки останова, пошаговое выполнение, пошаговое управление, инспекторы значений (текст, xml, пользовательские), отслеживание, отладка за потоком, условные точки останова, окно стека вызовов с возможностью перехода к коду на любом уровне. в стеке
    • (Чтобы быть справедливым, моя работа с Emacs + Slime, казалось, обеспечила часть этого, но я неравнодушен к подходу, основанному на графическом интерфейсе VS)

Мне действительно нравится ажиотаж вокруг Lisp, и я дал ему шанс.

Но есть ли что-то, что я могу сделать в Лиспе, что я не могу сделать также в C #? Это может быть немного более многословно в C #, но у меня также есть автозаполнение.

Чего мне не хватает? Почему я должен использовать Clojure / CL?

talonx
источник
4
Поскольку вы уже программируете в функциональном стиле, и похоже, что вы довольно сильно полагаетесь на инфраструктуру Windows, я не вижу убедительных причин для вас перейти с C #. Большинство всех, кого я знаю, используют Mac или Linux, поэтому многое зависит от толпы, с которой вы работаете (я использовал каждую версию Windows начиная с 3.1, но я все же предпочитаю работать с кроссплатформенным программным обеспечением и * nix системами в целом ... но тогда я не делаю никакой родной работы с графическим интерфейсом, все серверы и веб-интерфейс)
Шон Корфилд
2
Вы могли бы взглянуть на The Swine Before Perl . Это забавная беседа, которая представляет собой простой пример того, для чего нужны макросы.
Матиас Бенкард
4
«Я не видел ни одного примера, где идея макроса не могла бы быть реализована как функция» - я хотел бы увидеть, как вы написали бы ANDили ORкак функцию. Это может быть сделано (учитывая LAMBDA, что также является макросом), но я не вижу очевидного способа сделать это, который не будет полностью отстой.
1
«Пространства имен ... Кажется, что у Clojure это есть, CL, похоже, нет» - можете ли вы быть более точным в том, что вы ищете? Я на самом деле не использовал Clojure, но его пространства имен выглядят почти так же, как пакеты CL.
4
Джонатан: CL использует :(или ::для неэкспортированных символов) для именования символов в пакетах, например, ваш пример здесь будет использовать http:sessionи chat:session.

Ответы:

23

Макросы позволяют писать компиляторы без комфорта вашего языка. DSL в таких языках, как C #, обычно представляют собой интерпретатор времени выполнения. В зависимости от вашего домена это может быть проблематично по соображениям производительности. Скорость имеет значение , иначе вы будете кодировать на интерпретируемом языке, а не на C #.

Кроме того, макросы также позволяют учитывать человеческий фактор - какой синтаксис наиболее удобен для конкретного DSL? С C # мало что можно сделать с синтаксисом.

Таким образом, Lisp позволяет вам участвовать в разработке языка без ущерба для эффективности . И хотя эти проблемы могут не иметь для вас значения , они чрезвычайно важны, поскольку они лежат в основе всех полезных языков программирования, ориентированных на производство. В C # этот фундаментальный элемент в лучшем случае представлен вам в очень ограниченной форме.

Важность макросов не теряется на других языках - на ум приходит шаблон Haskell, camlp4. Но опять же, это проблема юзабилити - макросы Lisp на сегодняшний день, вероятно, являются наиболее удобной, но мощной реализацией преобразования во время компиляции.

Итак, в общем то, что люди обычно делают с такими языками, как C #, это сборка DSIL (предметно-ориентированных интерпретируемых языков). Lisp дает вам возможность создать что-то гораздо более радикальное, DSP (предметно-ориентированные парадигмы). Racket (ранее PLT-схема) особенно вдохновляет в этом отношении - у них есть ленивый язык (Lazy Racket), типизированный (Typed Racket), Prolog и Datalog, все идиоматически внедренные с помощью макросов. Все эти парадигмы предоставляют мощные решения для больших классов проблем - проблем, которые не могут быть решены с помощью императивного программирования или даже парадигм FP.

Роберт Харви
источник
3
Что мне показалось интересным в этом аргументе, так это то, что я никогда не сталкивался с возможностью (или просто полностью упускал это из виду в своем невежестве) для реализации DSL / DSIL. Не могли бы вы подробнее рассказать о мощи DSL? (Для обоих разработчиков и пользователей.) Это звучит , как это может быть большая вещь , я действительно не хватает.
15
@Jonathan Mitchem, вы уже используете много внешних DSL - файлов конфигурации, сценариев сборки, конфигураций ORM, генераторов визуального кода (например, редактора winforms), XAML, генераторов синтаксического анализатора и т. Д. Встроенные DSL даже лучше, чем вы им не нужен отдельный инструмент для сборки, и они обслуживаются на одном языке. И вы должны быть знакомы хотя бы с двумя встроенными DSL - регулярными выражениями и SQL.
SK-logic
Вау окей Я просто никогда не думал о них как о DSL. Теперь я намеренно отошел от всего этого, исходя из «всего, что я могу сделать с c #, я буду придерживаться c # for». Мне нравится придерживаться одного инструмента с последовательным поведением, лично. Но я понимаю ценность DSL в этих примерах.
2
@ Джонатан Митчем, проблема с любым конкретным инструментом заключается в том, что он не обязательно годится для данной цели. Вы должны выбрать разные инструменты для разных задач. Сила любого метаязыка, в том числе Lisp, заключается в том, что вам не нужно полностью переключаться на другой инструмент, поскольку вы можете вырастить свои собственные доменные инструменты поверх основного языка. Я предлагаю вам взглянуть на Nemerle, это будет легче понять для разработчика на C #, и его макросы почти так же мощны, как и Lisp.
SK-logic
3
«Мне нравится придерживаться одного инструмента ...» Правильно созданные DSL в Lisp никогда не скрывают всю мощь Lisp, поэтому у вас все еще есть один инструмент. Они просто добавляют в словарь таким образом, что делает кодирование для конкретной области более «естественным», то есть с лучшими абстракциями и общей организацией.
15

К счастью, почти все, что изначально было доступно только в Лиспе, перешло на многие другие современные языки. Самым большим исключением является философия «код - данные» и макросы.

Код - это данные (и макросы) - возможно, я не «получил» макросы, но я не видел ни одного примера, где идея макроса не могла бы быть реализована как функция

Да, макросы трудно понять. В общем, метапрограммирование трудно осуществить. Если вы видели какой-либо макрос, который мог бы быть реализован как функция, то программист делал это неправильно. Макросы следует использовать только тогда, когда функция не работает.

Пример макроса "hello world" - написать "if" в терминах cond. Если вы действительно заинтересованы в изучении возможностей макросов, попробуйте определить «my-if» в clojure, используя функции, и посмотрите, как оно ломается. Я не хочу быть таинственным, я просто никогда не видел, чтобы кто-то начинал понимать макросы только по объяснениям, но это слайд-шоу довольно хорошее вступление: http://www.slideshare.net/pcalcado/lisp-macros-in -20-й-отличая-Clojure-презентация

У меня были небольшие проекты, где я сохранял буквально сотни / тысячи строк кода с помощью макросов (по сравнению с тем, что было бы в Java). Большая часть Clojure реализована в Clojure, что возможно только благодаря макросистеме.

mblinn
источник
3
Не касаясь какого-либо кода, я пробежал сценарий реализации «если» без макросов в моей голове, как в Clojure, так и в C #. Это эффективно (или буквально) не может быть сделано. Я признаю, что это аккуратно. Но мне не хватает связи, как это полезно для меня. Что я могу сделать с макросами (кроме записи «если»), которые я не могу сделать с умным функционалом или OO-дизайном? «Как это может мне помочь» не является действительным критерием для оценки языка, но для оценки того, буду ли я его использовать. (Я действительно хочу, чтобы Лисп стоил перехода на него, но он не достиг точки превращения в жизнеспособную альтернативу.)
1
Мне понадобится немного времени, чтобы понять этот пример. Для меня «сохранение стандартного кода» обычно вызывает термин «рефакторинг», и поэтому объяснения меня не убедили. У меня есть решение, которое работает во всех случаях, когда я его применял. Тогда я думаю, что вопрос в том, как определить случаи, когда вы можете использовать макрос?
1
Я согласен с тем, что макросы полезны, но это не так, что my-if требует их, их можно записать как функцию более высокого порядка (см. Пример CL ниже). Вы действительно нуждаетесь в макросах, только если вы хотите просмотреть код или поместить его в новый лексический контекст. (defun my-if (test then &optional else) (cond (test (funcall then)) ('otherwise (funcall else))))
1
По сути, с функцией у вас есть выбор принять любой код в кавычках, который вы можете просмотреть, но в нем отсутствует лексический контекст, потому что вы гуляете и выполняете его в лексическом контексте вашей функции. Или вы можете принимать замыкания, которые сохраняют свой лексический контекст, но вы можете только вызывать, не обходить их или добавлять что-то в их лексический контекст. Для того, чтобы сделать и то, и другое, вам нужен макрос, который может обойти и обернуть код, прежде чем его расширение будет помещено в лексический контекст вызова макроса.
7
@Jonathan Mitchem, синтаксис LINQ - хороший пример того, что можно сделать с макросами, но вместо этого его нужно было реализовать в ядре языка, поскольку язык не поддерживает никакого достойного метапрограммирования.
SK-logic
14

Я не эксперт в Common Lisp, но я достаточно хорошо знаю и C #, и Clojure, так что, надеюсь, это полезная перспектива.

  • Простой синтаксис => мощность - Лиспс о самом простом синтаксисе, который мог бы работать. S-выражения - это все, что вам нужно. Как только вы нажали "(вызов функции arg1 arg2 arg3)", вы в основном получили его. Остальное - просто выбор правильных вызовов функций и аргументов. Кажется, это почти тривиально просто, но факт в том, что именно эта простота придает Лиспу столько силы и гибкости и, в частности, обеспечивает возможности метапрограммирования, которыми славится Лисп. например, если я хочу, чтобы макрос вызывал несколько разных функций для одних и тех же аргументов, я просто делаю что-то вроде следующего (не это не просто приложение функции времени выполнения - это макрос, который генерирует скомпилированный код, как если бы вы записали все вызовы отдельных функций). рукой):
(defmacro print-many [functions args]  
  `(do   
     ~@(map   
        (fn [function] `(println (~function ~@args)))   
        functions)))

(print-many [+ - * /] [10 7 2])  
19  
1  
140  
5/7
  • Благодаря невероятно простому синтаксису философия Lisp «код - данные» гораздо мощнее, чем все, что вы можете сделать с помощью композиции функций / шаблонов / обобщений и т. Д. Это больше, чем просто DSL, это генерация кода и манипулирование во время компиляции , как фундаментальная особенность языка. Если вы попытаетесь получить такого рода возможности в негомоикональной форме языке, таком как C # или Java, в конечном итоге вы в конечном итоге будете плохо изобретать Lisp. Отсюда и известное десятое правило Гринспуна: «Любая достаточно сложная программа на C или Fortran содержит специальную, неформально определенную, медленную реализацию половины Common Lisp». Если вам когда-либо приходилось изобретать в своем приложении язык шаблонов / управления потоком, полный Тьюринга, то вы, вероятно, знаете, что я имею в виду .....

  • Параллельность - это уникальная сила Clojure (даже по сравнению с другими Лиспами), но если вы считаете, что будущее программирования будет означать необходимость писать приложения, которые масштабируются на многоядерные машины, то вам действительно стоит задуматься об этом - это довольно новаторским. Clojure STM (программная транзакционная память) работает, потому что Clojure включает конструкции параллельности с неизменяемостью и без блокировки, основанные на новом разделении идентичности и состояния (см . Превосходное видео Рича Хики об идентичности и состоянии ). Было бы очень больно прививать такую ​​возможность параллелизма в среде языка / среды выполнения, где значительная часть API работает с изменяемыми объектами.

  • Функциональное программирование - Лисп подчеркивает программирование с функциями более высокого порядка. Вы правы в том, что его можно эмулировать в объектно-ориентированных объектах с замыканиями / объектами функций и т. Д., Но разница в том, что весь язык и стандартная библиотека разработаны, чтобы помочь вам писать код таким образом. Например, последовательности Clojure являются ленивыми , поэтому могут быть бесконечно длинными в отличие от ваших ArrayLists или HashMaps в C # / Java. Это делает некоторые алгоритмы намного проще для выражения, например, следующий реализует бесконечный список чисел Фибоначчи:

    (def fibs (lazy-cat '(0 1) (map + fibs (drop 1 fibs))))

  • Динамическая типизация - Лиспы, как правило, находятся на «динамическом» конце спектра функциональных языков программирования (в отличие от языков, подобных Haskell, с очень сильной и красивой концепцией статических типов). Это имеет как преимущества, так и недостатки, но я бы сказал, что динамические языки имеют тенденцию к повышению производительности программирования из-за большей гибкости. Такая динамическая типизация требует незначительных затрат производительности во время выполнения, но если это вас беспокоит, вы всегда можете добавить подсказки типов в свой код, чтобы получить статическую типизацию. По сути - вы получаете удобство по умолчанию и производительность, если вы хотите проделать дополнительную работу, чтобы добиться этого.

  • Интерактивная разработка - на самом деле я думаю, что вы можете получить что-то вроде REPL для C # 4.0, но в Лиспе это стандартная практика, а не новинка. Вам совсем не нужно делать цикл компиляции / сборки / тестирования - вы пишете свой код непосредственно в работающей среде и только позже копируете его в исходные файлы. Он учит вас совершенно другому способу кодирования, где вы сразу видите результаты и итеративно дорабатываете свое решение.

Несколько быстрых комментариев о вещах, которые вы видите как «отсутствующие»:

  • Как вы говорите, у Clojure есть пространства имен. На самом деле они являются динамическими пространствами имен: вы можете обновлять их во время выполнения - это обеспечивает некоторые неожиданные преимущества для интерактивной разработки. У меня было много забавных переопределений функций под носом запущенного потока или взлома живой структуры данных ....
  • Поддержка времени компиляции / разработки - не очень важно, если вы пишете код на REPL - вы просто делаете это и видите результат напрямую. Сказав это, Clojure начинает получать улучшенную поддержку IDE, например, плагин CounterClockwise для Eclipse .
  • Разработка GUI - Да, вам придется изучать новый API, но так будет всегда при переключении языков ... хорошая новость заключается в том, что API Java не так сложны, и теперь есть некоторые интересные Clojure- конкретные обертки / примеры, которые выглядят довольно простыми в использовании. Посмотрите этот вопрос о разработке GUI Clojure для некоторых хороших примеров
  • Отладка GUI: это работает с отладчиком GUI в Eclipse, предполагая, что вы используете CounterClockwise или Enclojure, если вы используете Netbeans. Сказав это, я не использую эту возможность - я считаю, что интерактивная отладка в REPL более продуктивна.

Лично я нахожу преимущества Clojure / Lisp довольно убедительными, и я не планирую возвращаться к C # / Java (помимо того, что мне нужно заимствовать все полезные библиотеки!).

Однако мне потребовалось несколько месяцев, чтобы по-настоящему обдумать все это. Если вы искренне заинтересованы в изучении Lisp / Clojure как полезного учебного процесса, ничто не заменит погружения и принуждения себя к реализации нескольких вещей .....

mikera
источник
1
Спасибо за отличный перечень идей. На самом деле я часто использую ленивые последовательности через конструкцию IEnumerable <> в C # (и не трогал ArrayList с 2005 года или около того), но я понимаю идею. Параллельные примитивы Clojure чрезвычайно впечатляют. Несколько лет назад я занимался грид-компьютингом в C # - параллелизмом на многих многоядерных машинах - и все еще верю, что это будущее. Вероятно, самая большая идея, которую я получил от всех: «вам действительно нужно просто покопаться и испытать это, это не может быть объяснено». Итак, я буду продолжать копать и продолжать испытывать.
1
Круто, рад, что помог - и это абсолютно правильный дух !!
Микера
10

C # имеет много функций, но смесь выглядит по-другому. То, что у некоторого языка есть особенность, еще не означает, что он прост в использовании, парадигматичен и хорошо интегрирован с остальным языком.

Common Lisp имеет такой микс:

  • s-выражения как синтаксис данных
  • код как данные приводит к макросам и другим методам символьных вычислений
  • динамический язык позволяет модифицировать во время выполнения (позднее связывание, MOP, ...)
  • строго типизированный, динамически типизированный
  • интерактивное использование с инкрементным компилятором или интерпретатором
  • Оценщик как основной механизм исполнения
  • управляемая память с помощью сборки мусора
  • Гибридный язык с интенсивным использованием императивного, функционального и объектно-ориентированного программирования. Другие парадигмы могут быть добавлены (правила, логика, ограничения, ...).

Теперь и другие языки, такие как C #, тоже это имеют. Но часто не с тем же акцентом.

C # имеет

  • C-подобный синтаксис
  • в основном императивный объектно-ориентированный, с некоторыми функциями FP
  • статически типизированный
  • в основном пакетное использование с пакетным компилятором
  • управляемая память с помощью сборки мусора

Не поможет, например, то, что в C # есть функции манипулирования кодом, если они не так широко используются, как в Lisp. В Лиспе вы не найдете много программ, которые не используют макросы интенсивно во всех видах простых и сложных способов. Использование манипулирования кодом действительно большая особенность в Лиспе. Эмуляция некоторых применений возможна во многих языках, но она не делает ее центральной функцией, как в Lisp. Для примера смотрите книги типа «На Лиспе» или «Практический общий Лисп».

То же самое для интерактивной разработки. Если вы разрабатываете большую систему САПР, большая часть разработки будет интерактивной из редактора и из REPL - непосредственно в работающее приложение САПР. Вы можете эмулировать большую часть этого в C # или других языках - часто путем реализации языка расширения. Для Lisp было бы глупо перезапускать разрабатываемое приложение CAD для добавления изменений. В этом случае система САПР будет также содержать расширенный Лисп, в который будут добавлены языковые функции (в форме макросов и символических описаний) для описания объектов САПР и их взаимосвязей (частично, содержаться, ...). Можно делать аналогичные вещи в C #, но в Lisp это стиль разработки по умолчанию.

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

Если вы работаете в среде Windows (я не работаю), то у C # есть преимущество, так как это основной язык разработки Microsoft. Microsoft не поддерживает какую-либо форму Lisp.

Ты пишешь:

  • Пространства имен. Даже со статическими методами мне нравится привязывать их к «классу», чтобы классифицировать их контекст (похоже, что у Clojure это есть, а CL нет).

Common Lisp не присоединяет пространства имен к классам. Пространства имен предоставляются пакетами символов и не зависят от классов. Вам необходимо переориентировать свой подход к объектно-ориентированному программированию, если вы используете CLOS.

  • Великолепная поддержка компиляции и разработки во время разработки системы типов позволяет мне определять «правильность» структур данных, которые я пропускаю, с ошибками, подчеркивается в реальном времени; Мне не нужно ждать, пока среда выполнения узнает, что улучшения кода (такие как использование подхода FP вместо императивного) автоматически предложены

Используйте компилятор Lisp. Он информирует вас о неизвестных переменных, может иметь рекомендации по стилю (в зависимости от используемого компилятора), дает подсказки по эффективности, ... Компилятор нажатий клавиш.

  • Инструменты разработки графического интерфейса: WinForms и WPF (я знаю, что Clojure имеет доступ к библиотекам Java GUI, но они мне совершенно чужды).

Коммерческие Lisps, такие как LispWorks и Allegro CL, предлагают аналогичные вещи под Windows.

  • Инструменты отладки графического интерфейса пользователя: точки останова, пошаговое выполнение, пошаговое управление, инспекторы значений (текст, xml, пользовательские), отслеживание, отладка за потоком, условные точки останова, окно стека вызовов с возможностью перехода к коду на любом уровне. в стеке (честно говоря, моя работа с Emacs + Slime, казалось, обеспечивала это, но я неравнодушен к подходу VS GUI)

Коммерческие Lisps, такие как LispWorks и Allegro CL, предлагают все это под Windows.

Райнер Йосвиг
источник
1
Моя критика не совсем о Лиспе. Я считаю, что они вполне способны. Я ищу то, что может делать / давать мне Лисп, чего еще не делал. Я полностью понимаю, что большинство разработчиков C # не используют многие «новые» языковые функции. Я думаю, что более важным является то, что я делаю, и, честно говоря, за пределами GUI я почти пишу в стиле 100% FP. FP был концептуальным скачком, но оно того стоило. Однако переключение на Лисп с того места, где я нахожусь, дает мало пользы. Я надеюсь найти причину, по которой я должен продолжать давать ей шанс.
@Jonathan Mitchem: C # на самом деле не похож на язык FP, даже если язык имеет некоторые функции, поддерживающие его, и некоторые библиотеки могут использовать их. Если вы хотите заниматься программированием на FP в эко-системе Microsoft, тогда F # может быть для вас.
@Rainer Нет, это не похоже на язык FP, но он может это сделать, и довольно компактно. И когда мне нужен / нужен императивный код или OO, я тоже могу это сделать. (немного не по теме: я на самом деле не считаю F # серьезным языком, в который стоит вникать, я бы лучше разбирался с монадами в Haskell. Но когда я был разработчиком C ++ и вышел C #, я не считал это «настоящий» язык тоже [и тогда это было не так, imho])
@ Джонатан Митчем: почему я должен смотреть? Я написал, что C # поддерживает некоторые функции FP. Он просто добавляется к императивному объектно-ориентированному языку и не делает его идиоматическим, как, скажем, в Lisp, Scheme и, особенно, по сравнению с SML, F #, Haskell или другими преимущественно функциональными языками. Я хочу сказать, что в C # возможна некоторая FP, но это не основная особенность.
5

Ренье Йосвиг сказал это лучше всего.

Для меня всю мощь Lisp невозможно понять, просто взглянув на список возможностей Lisp. В частности, для Лисп и Common Lisp целое больше, чем сумма частей. Это не просто REPL, s-выражения, макросы, отправка по нескольким методам, замыкания, пакеты, перезапуски CLOS, плюс X, Y и Z. Это весь гениальный интеграция. Это повседневный опыт, который очень сильно отличается от повседневного опыта других языков программирования.

Лисп выглядит по-другому, он используется по-разному, при его использовании можно по-другому подходить к программированию. Это элегантный, полный, большой и цельный. Это не без его собственных пятен и peccadilloes. Есть, конечно, сравнения с другими языками, которые могут быть сделаны там, где они не могут выйти вперед. Но Lisp ни в коем случае не является просто языком X с REPL и макросами или языком Y с мульти-методической диспетчеризацией и перезапуском.


источник
3
Код - это данные (и макросы). Возможно, я не «получил» макросы, но я не видел ни одного примера, где идея макроса не могла бы быть реализована как функция; это не меняет "язык", но я не уверен, что это сила

Как правило, макрос должен использоваться для чего-то, что не может быть выражено как вызов функции. Я не знаю, есть ли в C # условное переключение (подобное тому, что существует в C, как switch (form) {case ...}), но давайте предположим, что оно имеет и имеет почти те же ограничения ( требующий интегрального типа).

Теперь давайте предположим, что вам нужно что-то похожее на это, но отправляющее по строкам. В lisp (ну, в частности, в Common Lisp и, возможно, в других), это «просто» макрос, и если вы ограничиваете пользователя наличием постоянных строк (вероятно, не изнурительных) для сравнения, вы можете (время компиляции) вычислить минимальная последовательность тестов, чтобы определить, какой регистр соответствует (или использовать хеш-таблицу, возможно, для хранения замыканий).

Хотя может быть возможно выразить это как функцию (строка сравнения, список случаев и замыканий для выполнения), она, вероятно, не будет выглядеть как «обычный код», и именно здесь макросы lisp имеют определенный выигрыш. Вы , вероятно , использовали довольно много макросов или специальные формы TAHT являются макро-как, как defun, defmacro, setf, cond, loopи многое другое.

Vatine
источник
2

Это лучшая объяснительная статья, которую я нашел, которая берет читателя с поверхности адвокации Lisp, чтобы показать некоторые из более глубоких последствий используемых концепций:

http://www.defmacro.org/ramblings/lisp.html

Я помню, как читал в другом месте идею, подобную этой: другие языки приняли различные функции Lisp; сборка мусора, динамическая типизация, анонимные функции, замыкания для создания лучшего C ++ / C / Algol. Однако, чтобы получить полную мощность Lisp, вам нужны все его основные функции, и в этот момент у вас есть еще один диалект Lisp, отдельное семейство языков, которое существует в той или иной форме более 50 лет.

spacebat
источник