Есть ли в Лиспе какие-либо специальные функции, которые НЕ были приняты другими языками программирования?

35

Есть ли в Лиспе какие-либо специальные функции, которые НЕ были приняты другими языками программирования?

Под Лиспом я подразумеваю все языки программирования Лисп в целом. Мне рассказали, как прекрасен Лисп, и я знаю, что многие языки были вдохновлены Лиспом. Но есть ли в Лиспе эксклюзивная функция дизайна, которую просто невозможно сделать ни на каком другом языке?

Причина, по которой я задал этот вопрос, заключается в том, что недавно, будучи программистом-любителем, я начал изучать Clojure просто для удовольствия, и в результате я нашел много постов и комментариев, связанных с Лиспом, говоря только одно: «Лисп уникален ", но другие современные языки программирования уже приняли и украли много идей из Lisp, таких как условные выражения, рекурсия и функции первоклассного гражданина. И даже метапрограммирование может быть сделано многими языками.

Я что-то упустил, и Лисп все еще другой?

Или мне повезло, потому что другие современные языки украли все хорошие части из Lisp, так что нет необходимости копаться в скобках мира Lisp , и "Lisp был другим".

ICEX
источник
3
Поделиться своими исследованиями помогает всем. Расскажите нам, что вы пробовали и почему это не соответствует вашим потребностям. Это свидетельствует о том, что вы потратили время, чтобы попытаться помочь себе, избавляет нас от повторения очевидных ответов и, прежде всего, помогает получить более конкретный и актуальный ответ. Также см. Как спросить
комнат
3
@gnat Спасибо за совет, и я обновил свой вопрос :)
iceX
10
Одна из проблем заключается в том, что, если у языка есть определенное подмножество функций Lisp (например, S-выражений и макросов), люди утверждают, что это Lisp. Что, конечно, приводит к тому, что (по мнению этих людей) ни один не-Лиспский язык не может иметь этих возможностей.
9
Я думаю, что нет другого языка, где круглые скобки являются единственной формой группирования для всего :-)
Док Браун
Лисп как семья может быть не очень уникальным, но многие диалекты лиспов (Racket, CL, Scheme, Clojure) по-прежнему предлагают множество полезных / уникальных функций.
Даниэль Гратцер

Ответы:

28

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

8. Обозначение кода с использованием деревьев символов.

9. Весь язык всегда доступен. Нет реального различия между временем чтения, временем компиляции и временем выполнения. Вы можете компилировать или запускать код во время чтения, читать или запускать код во время компиляции, а также читать или компилировать код во время выполнения.

Комментарий обращается к каждой точке и называет популярные языки, где эта функция доступна.

8, который (с 9) делает возможным использование макросов на Лиспе, до сих пор остается уникальным для Лиспа, возможно, потому, что (а) ему нужны эти парены, или что-то столь же плохое, и (б) если вы добавите это последнее увеличение мощности вы больше не можете утверждать, что изобрели новый язык, но только разработали новый диалект Lisp; -)

Обратите внимание, что эта статья была в последний раз пересмотрена в 2002 году, и за последние 11 лет появилось большое количество новых языков, некоторые из которых могут включать все эти функции Lisp в свой дизайн.

Грег Хьюгилл
источник
2
Эти функции не являются уникальными для Lisp (и напрямую производными вариантами) и не были достаточно долгое время.
Донал Феллоуз
21
@iceX: Разница между JavaScript и такими языками, как Lisp, Smalltalk, Self, Newspeak, APL, Factor, Forth и т. д., заключается в том, что в JavaScript программы «мертвы». Это текстовые файлы. Вы убиваете запущенную программу, редактируете текстовый файл, затем запускаете совершенно новую копию программы. В этих других (так называемых «живых» средах) вы никогда не останавливаете запущенную программу, сама запущенная программа представляет собой набор объектов в памяти, которыми вы манипулируете так же, как манипулируете любым другим объектом во время его работы . (Примечание: это не относится к Clojure, но большинство более старых Лиспов делают это таким образом.)
Йорг Миттаг,
2
@ JörgWMittag Ух ты ... Итак, языки программирования, такие как Clojure, Clojurescript, lispyscript, на самом деле не являются "настоящим lisp", потому что они не могут изменить свой код так, как это делает старая школа Lisp, как Common Lisp. Но ... если они не могут это изменить ... зачем использовать S-выражение, которое, как я думал, было использовано для манипулирования кодом ... (ощущение, будто я только что упал в глубокую темную кроличью нору)
iceX
4
@iceX: Многие языки имеют evalили похожи, и многие могут выполнять метапрограммирование, например, Haskell Template Haskell. (Возможно) уникальная вещь в Lisp заключается в том, что представление данных, кода и метакода одинаково - не только в синтаксисе, но и в действительности одно и то же.
tdammers
2
@iceX Eval - это только одна его часть, но не вся. В Лиспе вы можете выполнять код во время компиляции. Вы можете выполнить код во время чтения. Да, clojure поддерживает весь динамизм Lisp, у него есть макросы, макросы чтения и eval, а также возможность присоединить REPL к работающей программе, чтобы изменять ее на лету.
каменная металлургия
15

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

Сверх того, условия - это то, чего я не видел ни на одном другом языке. Подумайте об «исключениях», но в тех случаях, когда стек вызовов не разматывается, и когда вызывающая сторона может отправлять значение восстановления на сайт исключений, но не нарушая стек вызовов между обработчиком и источником исключения. Если честно, это на самом деле просто специальное применение продолжений, поэтому Ruby и Scheme (по крайней мере) могут это сделать.

Макросистема Лиспа извлекает выгоду из регулярности / гомоиконичности, но Scala планирует включить их в качестве стабильной функции в 2.12, и Template Haskell претендует на аналогичные функции. Я бы сказал, что они будут более сложными по синтаксису, чем с Lisp, но генерация кода во время компиляции существует независимо.

Если задуматься, то прямое построение форм - это всего лишь один вид макросов, доступных в Лиспе: я не видел ни одного эквивалента макросов компилятора или читателя где-либо еще.

Способность некоторых диалектов (например, SBCL ) сохранять законченный, восстанавливаемый образ процесса - это круто, но, опять же, это не уникально: Smalltalk делал это десятилетиями.

Многие другие языки допускают деструктуризацию присваивания при возврате массивов, но подход # 'values ​​и #' множественные-значения-привязки / let-values ​​по-прежнему специфичен для Common Lisp и Scheme (которые все еще могут выполнять «обычную» деструктуризацию). ). 'Wantarray' в Perl позволяет функции определять, вызывается ли она в скалярном, списочном или пустом контексте, поэтому она может корректировать свое возвращаемое значение аналогичным (-ish) способом, но я не видел "истинных" множественных возвращаемых значений вне Схемы / кл.

Что касается языковых возможностей, то, вероятно, Лисп не так много может сделать, чего не могут другие языки (полнота Тьюринга - это то, чем он является). Что это , однако, является языком , где код выражается в терминах своих собственных структур данных, что делает большую идею ™ -Вот коды данных то , что относительно легко работать.

Дэнни Вудс
источник
3
Макросы Scala намного менее мощны, чем макросы Lisp, а также макросы TH, гигиенические макросы Scheme и т. Д. Не менее мощная система может быть найдена в MetaLua и Converge.
SK-logic
4

После стольких десятилетий я не думаю, что в Lisp есть что-то эксклюзивное. Но даже сегодня есть много интересных вещей, которые трудно найти за пределами Лиспа. Несколько вещей, которые приходят на ум:

  • Высококачественная объектная система со сложными мета-протоколами (например, CLOS) не пользуется удаленной популярностью.
  • время от времени где-то появляются мульти-методы, но большинство людей никогда о них не слышали.
  • Как уже отмечали другие, система условий довольно сложна по сравнению с популярными механизмами обработки исключений.
  • Компактное представление семантики языка (eval), расширяющий возможности подход к определению языка и доступ к нему для простых глубоких адаптаций (см. SICP ) - «эквивалентные» функции современных популярных языков просто не имеют одинаковых свойств.

Наконец, у Lisp можно многому научиться, но не о самом языке, а о том, что стало частью истории Lisp и затерялось во времени. Например INTERLISP, Symbolics Роды и т.д ... если вы никогда не кладите руки на Роды, увидеть эту comp.lang.lisp нить , где Кент Питмэн описывает , как «Emacs является лишь бледной тенью Zmacs Роды в» - который все обеспечиваемых имея мощную систему Lisp, частью которой был Zmacs, которая работала на машине Lisp.

Тиаго Сильва
источник
Я никогда не видел хорошего объяснения мультиметодов, которое отличало бы их от перегруженных методов , стандартная функция почти во всех современных императивных языках, за исключением того факта, что мультиметодная диспетчеризация разрешается динамически во время выполнения и поэтому намного медленнее, чем использование перегруженных методов, которые разрешаются во время компиляции.
Мейсон Уилер
У них есть важные различия. Если у вас возникли проблемы с поиском ресурса по этому вопросу, вы всегда можете создать новый вопрос здесь ..
Тиаго Сильва
У Джулии мультиметоды, а параметрический полиморфизм Хаскелла подобен мультиметодам. Существуют способы моделирования мультиметодов на многих языках. Система условий - это то, что мне действительно нужно (отредактируйте и продолжайте, хотя я видел это для отладчиков C #).
aoeu256
4

Это не обязательно определенная особенность . Это весь внешний вид и то, как определенные наборы функций работают вместе.

JavaScript или Java имеют много функций Lisp (виртуальная машина, компилятор / оценщик, сборщик мусора и т. Д.). Но, например, в JavaScript отсутствует часть символьного программирования, ему не хватает математических возможностей (внутренне он имеет только плавающие значения), ему не хватает обработки ошибок и т. Д.

Многие системы Common Lisp оптимизированы для способа разработки, при котором каждый постепенно расширяет новое программное обеспечение, расширяя язык Lisp в различных измерениях, используя различные методы метапрограммирования - без перезапуска программного обеспечения в течение длительного времени. Таким образом, он должен быть гибким и расширяемым, но в то же время он должен быть надежным. Изменение языка (макросы - это, по сути, способ расширения компилятора для пользователя) без сбоя программы.

Теперь что-то вроде JavaScript также используется для расширения программы, обычно это веб-браузер. Но большую часть времени никто не занимается метапрограммированием на JavaScript - кроме некоторого хакерства ООП .

Пример:

Можно реализовать общее продвинутое математическое программное обеспечение для области компьютерной алгебры в основном двумя способами: написать движок на C со специализированным языком наверху (например, Mathematica ) или на более продвинутом диалекте Lisp. Macsyma / Maxima в Common Lisp, Сокращение в Standard Lisp, Аксиома в Common Lisp.

(Есть также один или несколько написано на Python.)

Существует не так много систем, которые предлагают набор функций чего-то вроде Axiom , который работает поверх Common Lisp.

Что делает Лисп привлекательным для приложений такого типа, так это сочетание функций: продвинутых базовых математических функций (bignums, ratios, ...), символьных вычислений, интерактивного компилятора и т. Д. Вполне возможно получить эти вещи, реализовав их в Уровень языка. Таким образом, будет реализовано 50% или более типичной системы Lisp.

Райнер Йосвиг
источник
2

Не настолько, насколько я знаю. Forth легко так же динамичен, как Lisp, возможно, тем более, поскольку динамический код в Forth выглядит как обычный код Forth, в то время как макросы Lisp, как правило, используют функции, отличные от обычного кода Lisp ( по крайней мере, в Clojure я никогда не использовал синтаксические кавычки вне макроса) и в результате они выглядят действительно отличающимися от обычного кода на Лиспе. В качестве примера того, насколько динамичен Forth, вот способ реализации комментариев в Forth :

: (   41 word drop ; immediate
( That was the definition for the comment word. )
( Now we can add comments to what we are doing! )
stonemetal
источник
1
Каким бы забавным ни казался Форт, я всегда находил его безнадежно непрозрачным и неловким, возможно, потому что он основан на стеке и все перевернуто.
Роберт Харви
2
Из любопытства, что вы подразумеваете под «отделением от основной части языка»? Макросы в Лиспе имеют полный доступ ко всем функциям, определенным в момент определения макроса, и любую из них можно использовать для создания формы, в которую расширяется макрос. Это может включать информацию, полученную из базы данных и / или сервера. Ваш пример комментария может быть определен как: (комментарий defmacro (& rest body)), не так ли?
Дэнни Вудс
1
@DannyWoods Я имею в виду, что макросы не похожи на обычный код. По крайней мере, в clojure вы можете отличить код макроса от обычного кода, потому что он интенсивно использует синтаксическую кавычку, сплайсинг без кавычек и т. Д., Что необычно в обычном коде. Этот пример четвертого кода, который я дал, выглядит как обычный код, пока вы не увидите немедленный. Перечитывая мой ответ, он просто слабо выражен.
каменный металл
1
@stonemetal Не беспокойтесь, но стоит отметить, что в синтаксических кавычках нет ничего специфичного для макросов, ни в Common Lisp, ни в Clojure. Иногда бывает удобно иметь обратные выражения в регулярных определениях функций, а макросы можно создавать вручную с помощью простых списков (хотя вам нужно сделать это один или два раза, чтобы решить, что синтаксическая кавычка - хорошая вещь!)
Дэнни Вудс,
1
Чтобы быть справедливым, то же самое можно сделать в Лиспе, зарегистрировав пользовательский макрос для чтения.
Фьярри
2

Лисп имеет много диалектов, и каждый из них имеет свой набор функций. Моя любимая особенность, которая вряд ли будет принята на любом другом языке - это «стек спагетти» от Interlisp .

Стек спагетти похож на укупорку, но на стероидах. Он сохраняет не только текущую функцию, но и весь контекст до верха стека. Что-то вроде подпрограммы , за исключением того, что вы можете создавать их произвольно, что приводит к иерархии стековых контекстов.

ddyer
источник
Не знал этого, собираюсь проверить это, спасибо за ваш ответ :)
iceX
7
Это то же самое, что продолжение Схемы?
Никола Мусатти
1
@NicolaMusatti, «стек спагетти» - это общая стратегия реализации для продолжения, подобного Схеме (которую можно вызывать после того, как функция, которая их создала, вернулась).
Alex D