В StackOverflow и на этом сайте нет недостатка в расплывчатых вопросах "Scheme vs Common Lisp", поэтому я хочу сделать этот вопрос более сфокусированным. Вопрос для людей, которые закодировали на обоих языках:
Во время написания кода на Схеме, какие конкретные элементы вашего опыта в Common Lisp вам больше всего не хватало? Или, наоборот, при кодировании в Common Lisp, что вы упустили из кодирования в Scheme?
Я не обязательно имею в виду только языковые особенности. Следующее - все действительные вещи, чтобы пропустить, что касается вопроса:
- Конкретные библиотеки.
- Особенности сред разработки, таких как SLIME, DrRacket и др.
- Особенности конкретных реализаций, такие как способность Gambit записывать блоки кода на C прямо в ваш источник Scheme.
- И конечно, языковые особенности.
Примеры ответов, на которые я надеюсь:
- «Я пытался реализовать X в Common Lisp, и если бы у меня были первоклассные продолжения Scheme, я бы просто сделал Y, но вместо этого я должен был сделать Z, что было больше боли».
- «Сценарии процесса сборки в моем проекте Scheme становились все более болезненными, так как мое дерево исходных текстов росло, и я связывал все больше и больше библиотек C. Для моего следующего проекта я вернулся в Common Lisp».
- «У меня есть большая существующая кодовая база C ++, и для меня, возможность встраивать вызовы C ++ непосредственно в мой код Scheme Gambit полностью стоил любых недостатков, которые Scheme может иметь по сравнению с Common Lisp, даже включая отсутствие поддержки SWIG».
Итак, я надеюсь на военные истории, а не на общие настроения, такие как «Схема - более простой язык» и т. Д.
Ответы:
Я получил степень бакалавра в области когнитивной науки и искусственного интеллекта. После этого у меня было введение из одного курса в Lisp. Я думал, что язык интересен (как в «элегантном»), но не особо задумывался о нем, пока не наткнулся на Десятое Правило Гринспуна гораздо позже:
Гринспен утверждал (частично), что многие сложные программы имеют встроенные интерпретаторы. Вместо того, чтобы встроить интерпретатор в язык, он предположил, что было бы более разумно использовать язык, подобный Лиспу, который уже имеет встроенный интерпретатор (или компилятор).
В то время я работал над довольно большим приложением, которое выполняло пользовательские вычисления с использованием специального интерпретатора для пользовательского языка. Я решил попробовать переписать его ядро на Лиспе в качестве масштабного эксперимента.
Это заняло примерно шесть недель. Оригинальный код был ~ 100 000 строк Delphi (вариант Паскаля). В Лиспе это было сокращено до ~ 10000 строк. Еще более удивительным было то, что двигатель Lisp работал в 3-6 раз быстрее. И имейте в виду, что это была работа новичка Лиспа! Весь этот опыт был довольно откровением для меня; Впервые я увидел возможность сочетать производительность и выразительность на одном языке.
Некоторое время спустя, когда я начал работать над веб-проектом, я прослушал несколько языков. Я включил в смесь Lisp и Scheme. В конце концов я выбрал реализацию схемы - схему Chez . Я был очень доволен результатами.
Веб-проект представляет собой высокопроизводительный «механизм выбора» . Мы используем Scheme разными способами, от обработки данных до запроса данных и генерации страниц. Во многих местах мы фактически начинали с другого языка, но в итоге перешли на Scheme по причинам, которые я кратко опишу ниже.
Теперь я могу ответить на ваш вопрос (хотя бы частично).
Во время прослушивания мы рассмотрели различные реализации Lisp и Scheme. Со стороны Lisp мы рассмотрели (я полагаю) Allegro CL, CMUCL, SBCL и LispWorks. Со стороны Схемы мы смотрели (я полагаю) Биглоо, Курица, Чез, Гамбит. (Выбор языка был давным-давно; поэтому я немного туманен. Я могу выкопать некоторые заметки, если это важно.)
Мы сразу искали: а) нативные темы и б) поддержку Linux, Mac и Windows. Эти два условия объединили всех, кроме (я думаю) Аллегро и Чеза - поэтому, чтобы продолжить оценку, нам пришлось ослабить требование многопоточности.
Мы собрали набор небольших программ и использовали их для оценки и тестирования. Это выявило ряд проблем. Например: некоторые реализации имели дефекты, которые мешали выполнению некоторых тестов до завершения; некоторые реализации не могут компилировать код во время выполнения; некоторые реализации не могли легко интегрировать скомпилированный код времени выполнения с предварительно скомпилированным кодом; у некоторых реализаций были сборщики мусора, которые были явно лучше (или явно хуже), чем у других; и т.п.
Для наших нужд только три коммерческие реализации - Allegro, Chez и Lispworks - прошли наши первичные испытания. Из трех только Chez прошел все тесты с летающими цветами. В то время я думал, что у Lispworks не было собственных потоков на какой-либо платформе (я думаю, что они есть сейчас), и я думаю, что у Allegro были только собственные потоки на некоторых платформах. Кроме того, у Allegro была плата за лицензию «позвони нам», что мне не очень понравилось. Я считаю, что у Lispworks не было платы за время выполнения, а у Chez была простая (и очень разумная) схема (и она вступила в силу только в том случае, если вы использовали компилятор во время выполнения).
Произведя несколько значительных кусков кода как на Лиспе, так и на Схеме, вот некоторые точки сравнения и сравнения:
Среды Лиспа гораздо более зрелые. Вы получаете намного больше за доллар. (Сказав это, больше кода также означает больше ошибок.)
Среды Лиспа гораздо сложнее изучать. Вам нужно гораздо больше времени, чтобы стать опытным; Common Lisp - это огромный язык - и это прежде, чем вы перейдете к библиотекам, которые коммерческие реализации добавляют к нему. (Сказав это, синтаксический случай Scheme гораздо более тонкий и сложный, чем любая другая вещь в Lisp.)
В средах Lisp может быть несколько сложнее создавать двоичные файлы. Вам нужно «встряхнуть» ваше изображение, чтобы удалить ненужные биты, и если вы не будете правильно выполнять свою программу во время этого процесса, вы можете позже столкнуться с ошибками во время выполнения. , Напротив, с Chez мы компилируем файл верхнего уровня, который включает в себя все остальные файлы, которые ему нужны, и мы закончили.
Я уже говорил, что в конечном итоге мы использовали Scheme во многих местах, которые мы изначально не собирались делать. Почему? Я могу думать о трех причинах из головы.
Сначала мы научились доверять Chez (и его разработчику, Cadence). Мы много просили от инструмента, и он постоянно доставлял. Например, Chez исторически имел незначительное количество дефектов, и его менеджер памяти был очень, очень хорош.
Во-вторых, мы научились любить представление, которое мы получили от Chez. Мы использовали что-то похожее на язык сценариев - и мы получили скорость нативного кода от этого. Для некоторых вещей это не имело значения - но это никогда не ранило, а иногда это очень помогало.
В-третьих, мы научились любить ту схему, которую могла предоставить абстракция. Кстати, я имею в виду не только макросы; Я имею в виду такие вещи, как замыкания, лямбды, хвостовые вызовы и т. Д. Как только вы начинаете думать в этих терминах, другие языки кажутся довольно ограниченными по сравнению.
Схема идеальна? Нет; это компромисс. Во-первых, это позволяет отдельным разработчикам быть более эффективными - но разработчикам труднее ухватиться за код друг друга, потому что в Схеме отсутствуют указатели, которые есть в большинстве языков (например, для циклов) (например, существует миллион способов сделать это). для цикла). Во-вторых, гораздо меньше разработчиков, с которыми можно общаться, брать на работу, брать кредиты и т. Д.
Подводя итог, я думаю, я бы сказал: Lisp и Scheme предлагают некоторые возможности, не так широко доступные где-либо еще. Эта возможность является компромиссом, поэтому лучше иметь такую, которая имеет смысл в вашем конкретном случае. В нашем случае определяющие факторы между тем, использовать ли Lisp или Scheme, были в большей степени связаны с очень фундаментальными функциями (поддержка платформы, потоки платформы, компиляция во время выполнения, лицензирование во время выполнения), чем с возможностями языка или библиотеки. Опять же, в нашем случае это тоже было компромиссом: с Chez мы получили основные функции, которые хотели, но мы потеряли обширные библиотеки, имеющиеся в коммерческих средах Lisp.
Также, чтобы повторить: мы смотрели на различные Лиспы и Схемы очень давно; с тех пор все они развивались и совершенствовались.
источник
Я обычно не люблю вставлять ссылку в качестве ответа, но я написал статью в блоге именно об этом. Это не является исчерпывающим, но это дает понять некоторые основные моменты.
http://symbo1ics.com/blog/?p=729
Редактировать : вот основные моменты:
TERPRI
,PROGN
И т.д. Схема обычно имеет очень осмысленные имена. Это что-то упущено в CL.list
" to "lst
" в Схеме.syntax-rules
все нормально и круто, пока ты не захочешь по-настоящему взломать некоторые вещи. С другой стороны, гигиенические макросы иногда пропускаются в CL. Отсутствие стандартного способа сделать это означает заново изобретать колесо.Хотя я говорил от первого лица чуть выше, должно быть ясно, что я скучаю, а что нет.
[Я извиняюсь, если они слишком общие. Кажется, вам может понадобиться более конкретная информация. В этом посте есть некоторые особенности.]
источник
Недавно я начал домашний проект, используя библиотеку, которая имеет версию C и версию Java. Я хотел использовать Lisp для проекта и потратил около месяца на колебания между использованием Common Lisp, Scheme или Clojure. У меня есть некоторый опыт работы со всеми тремя, но только с игрушечными проектами. Я расскажу вам немного о своем опыте с каждым из них, прежде чем рассказать, какой из них я выбрал.
PLT Racket имеет хорошую IDE, которая не только позволяет вам оценивать выражения из редактора, но также позволяет вводить скобки вместо скобок, переключая их обратно на скобки, где это уместно. Racket также имеет большой набор библиотек с возможностью установки и даже более доступных для загрузки. Визуальный отладчик также полезен.
Моя реализация Common Lisp (SBCL) не имеет IDE, но обычно в реализациях CL с открытым исходным кодом используется Emacs и SLIME. Эта комбинация может быть очень эффективной. Наряду с возможностью оценивать выражения по мере их ввода в исходный файл, есть также REPL, в котором есть все доступные для редактирования команды emacs, поэтому копирование кода может эффективно выполняться в обоих направлениях. Даже объекты, отображаемые в буфере REPL, можно копировать и вставлять.
Alt+(
иAlt+)
эффективны для работы с соответствующими скобками и отступами.Все вышеперечисленные функции Emacs также доступны для Clojure. Мой опыт редактирования с Clojure похож на тот, что был в Lisp. Java-взаимодействие работало нормально, и я хотел бы сделать проект Clojure, как только он станет зрелым.
Я смог получить доступ к библиотеке, используя все три (Common Lisp, Racket и Clojure), но в итоге я выбрал Common Lisp для проекта. Решающим фактором было то, что FFI было намного проще использовать в Common Lisp. У CFFI есть очень хорошее руководство с примером кода и подробными объяснениями каждого метода. Я был в состоянии обернуть 20 функций C днем, и с тех пор мне не приходилось трогать код.
Другим фактором было то, что я больше знаком с Common Lisp, чем с Clojure или R6RS Scheme. Я прочитал большинство книг Практического Общего Лиспа и Грэма, и я доволен Hyperspec. Это еще не очень «шустрый» код, но я уверен, что он изменится, когда я приобрету больше опыта.
источник
Я программирую на CL и Racket.
Сейчас я разрабатываю веб-сайт в Common Lisp и написал набор собственных программ для моего предыдущего работодателя в Racket.
Для внутреннего кода я выбрал Racket (тогда он назывался PLT Scheme), потому что работодателем был магазин Windows, и я не мог заставить их платить за LispWorks. Единственной хорошей реализацией CL с открытым исходным кодом для Windows была (и остается) CCL, для которой требуется поддержка SSE в процессоре. Работодатель, будучи дешевым, использовал оборудование каменного века. Даже если у работодателя действительно было приличное оборудование, единственной библиотекой графического интерфейса в Common Lisp является McCLIM, который работает только в Unix. Racket имеет хорошую библиотеку графического интерфейса, которая работает как в Unix, так и в Windows, что имело решающее значение для успеха моего проекта.
Я потратил больше года на то, чтобы смириться с примитивным редактором DrRacket. EMACS не смог превратить версию Racket с графическим интерфейсом, которая тогда называлась MrEd, в неполный список ошибок в Windows. Мне пришлось обойтись без возможности оценить выражение на курсоре одним нажатием клавиши. Вместо этого мне пришлось вручную выбрать S-выражение, скопировать его, щелкнуть окно REPL (потому что на него не нужно нажимать клавиши), а затем вставить S-выражение. Мне также пришлось обходиться без редактора, который мог бы показать ожидаемые аргументы функции или макроса, который я использовал. DrRacket не заменит SLIME.
Работодатель использовал закрытую базу данных со сложным XML-API, который требовал загрузки на первый взгляд ненужной информации, чтобы иметь возможность ответить на свою версию запроса SELECT. Я решил использовать HTMLPrag как для передачи XML в этот API, так и для анализа ответов. Это работало отлично.
Мне пришлось изучить сверхсложную макросистему Racket «синтаксис-регистр», чтобы написать макрос, который позволял бы мне взаимодействовать с чрезмерно сложным XML API, печатая формы, похожие на SQL. Эта часть была бы намного проще, если бы в моем распоряжении был DEFMACRO. Тем не менее, конечный результат был по-прежнему без шва, хотя потребовалось больше усилий для достижения.
Кроме того, мне пришлось обходиться без макроса LOOP от Common Lisp. Racket начал предоставлять альтернативу только после того, как я написал большую часть кода, и альтернатива по-прежнему отстой по сравнению с LOOP (хотя команда разработчиков Racket настаивает, что она лучше - они просто ошибаются). Я закончил тем, что написал много именованных форм LET, которые использовали «car» и «cdr» для перебора списков.
Говоря об автомобиле и CDR, нет ничего более расстраивающего, чем интерпретация Схемы (car '()) как ошибки. Я воспользовался чувствительностью к регистру Racket и реализовал CAR и CDR, которые имеют семантику Common Lisp. Однако разделение '() и #f делает гораздо менее полезным возвращение' () в качестве значения по умолчанию.
Я также в конечном итоге повторно внедрил UNWIND-PROTECT и изобрел свою собственную систему перезапуска, чтобы заполнить пробел, оставленный Racket. Сообщество Racket должно понять, что перезапуски очень полезны и просты в реализации.
Форма значений Racket была слишком многословна, поэтому я применил MULTIPLE-VALUE-BIND. Это было абсолютно необходимо, потому что Racket требует , чтобы вы получили все сгенерированные значения, используете ли вы их или нет.
Позже я попытался написать клиент eBay XML API в Common Lisp, но обнаружил, что у него нет ничего похожего на HTMLPrag. HTMLPrag чертовски полезен. Я закончил делать этот проект в Racket. Я экспериментировал со средствами Racket Literate Programming, только чтобы обнаружить, что я единственный программист на Земле, который считает правильно написанный грамотный код сложнее редактировать, чем обычный код, или неправильно написанный грамотный код с «чрезмерным количеством комментариев».
Мой новый проект выполняется в Common Lisp, и это был правильный выбор, потому что сообщество Racket просто не верит в параллелизм, который необходим для этого проекта. Единственное, что я думал, что мог пропустить из Ракетки, это продолжения. Тем не менее, я смог сделать то, что мне было нужно, с помощью перезапусков, и, оглядываясь назад, возможно, мог бы сделать это с помощью простого закрытия.
источник
cond
формы) и ошибки (правильно ли я написал тест завершения цикла в этот раз?) Даже сегодня у меня складывается впечатление эта ракетка в основном предназначена для студентов, а не профессиональных программистов. Каждый раз, когда я слышу о ком-то, кроме меня, они используют подъязык «Начинающий студент», и это для класса.Схема разработана с учетом отдельной компиляции. Как следствие, мощность его макросов часто сильно ограничена, даже с расширениями, которые допускают дефмакро в стиле Common Lisp вместо плохой, ограничивающей гигиенической макросистемы. Не всегда возможно определить макрос, который определяет другой макрос, предназначенный для немедленного использования в следующей строке кода. И такая возможность необходима для реализации эффективных компиляторов eDSL.
Излишне упоминать, что реализации Scheme только с гигиеническими макросами R5RS для меня едва ли полезны, поскольку мой стиль метапрограммирования не может быть адекватно переведен на гигиену.
К счастью, есть реализации Scheme (например, Racket), которые не имеют этого ограничения.
источник